Unity iOS が現在サポートしていない機能
iOSでのクラッシュ時バグレポート方法 / Reporting crash bugs on iOS

iOSデバイスでのトラブルシューティング

iOSにおいて,あなたのゲームがUnityエディタで完璧に動作することができるが,その後,動作しないか,多分,実際のデバイス上で起動しないなど,いくつかの状況があります。 問題は,多くの場合,コードやコンテンツの品質に関連してます。このセクションでは,最も一般的なシナリオについて説明します。

ゲームはしばらく後に応答を停止します。 Xcodeはステータスバーに“interrupted(中断)”と表示します。

これが起こる理由はいくつかあり,よくある原因は次のとおりです。:

  1. 初期化されていない変数を使うなどのスクリプトエラー 1.サードパーティのThumb(code)コンパイルしたネイティブライブラリ使うこと。このようなライブラリは,iOS SDKのリンカの既知の問題を誘発し,ランダムなクラッシュを引き起こす可能性があります。
  2. シリアライズ可能スクリプトプロパティのパラメータとして(例 List<int>, List<SomeStruct>, List<SomeEnum>, etc)バリュータイプを一緒にジェネリックタイプを使うこと。 1.マネージコードストリッピングが有効になっている時,リフレクションを使うこと
  3. ネイティブプラグインインターフェイスエラーのとき(マネージコードメソッドのシグネチャは,ネイティブコード関数のシグネチャと一致していません)。 Xcodeのデバッガコンソールからの情報は,多くの場合,これらの問題を検出するのに役立ちます(Xcode menu: View > Debug Area > Activate Console)。

Xcodeコンソールに "プログラムがシグナル : “SIGBUS” または EXCBADACCESS errorを受信した”と表示されるとき

アプリケーションが NullReferenceException を受信したとき,このメッセージは通常,iOSデバイスに表示されます。障害が起こった場所を把握する2つの方法:

マネージドスタックトレース

4以来Unityには,NullReferenceExceptionのソフトウェアベースの処理が含まれています。AOTコンパイラには,null参照する毎,または変数がオブジェクトにアクセスする毎に簡単にチェックする方法が含まれています。この機能が開発ビルドのために有効になっている理由であり,スクリプトのパフォーマンスに影響します。(基本ライセンスユーザーは,ビルド設定ダイアログの “開発ビルド” オプションが有効で十分であり,iOSプロライセンスユーザーは,追加的に ”スクリプトのデバッグ“オプションを有効にする必要があります)。 すべてが正しく行われ,実際に障害が.NETコードで発生している場合,その後,EXC_BAD_ACCESSは表示されません。代わりに,.NET例外テキストはXcodeのコンソールに出力されます(あるいはあなたのコードは,単に ”catch"文でそれを処理します)。典型的な出力は次のようになります。:

Unhandled Exception: System.NullReferenceException: A null value was found where an object instance was required.
  at DayController+$handleTimeOfDay$121+$.MoveNext () [0x0035a] in DayController.js:122 

これは,障害がDayControllerクラスのコルーチンとして動作しているhandleTimeOfDaymメソッドで起こったことを示しています。それがスクリプトコードであれば,通常,正確な行番号を通知します(例えば,“DayController.js:122”)。問題のある行は,以下のようなものが考えられます。

 Instantiate(_imgwww.assetBundle.mainAsset);

例えば,スクリプトは最初にそれが正しくダウンロードされたことを確認せずにアセットバンドルにアクセスした場合に発生する可能性があります。

ネイティブスタックトレース

ネイティブスタックトレースは,障害調査のためのより強力なツールですが,使用する際,いくつかの専門知識を必要とします。さらに一般的にネイティブエラー(ハードウェアメモリアクセス)が起きた後には続行できません。ネイティブスタックトレースを取得するには,Xcodeのデバッガコンソールにbt allと入力します。出力されたスタックトレースを慎重に調べると - エラーが発生した場所についてのヒントを含んでいることがあります。次のように表示されることがあります。:

...
Thread 1 (thread 11523): 

1. 0 0x006267d0 in m_OptionsMenu_Start ()
1. 1 0x002e4160 in wrapper_runtime_invoke_object_runtime_invoke_void__this___object_intptr_intptr_intptr ()
1. 2 0x00a1dd64 in mono_jit_runtime_invoke (method=0x18b63bc, obj=0x5d10cb0, params=0x0, exc=0x2fffdd34) at /Users/mantasp/work/unity/unity-mono/External/Mono/mono/mono/mini/mini.c:4487
1. 3 0x0088481c in MonoBehaviour::InvokeMethodOrCoroutineChecked ()
...

まず第一に, “Thread 1” のスタックトレースを見つける必要があり,それがメインスレッドです。スタックトレースの最初の行は,エラーが発生した場所を指しています。この例では,トレースはNullReferenceExceptionが “OptionsMenu” スクリプトの “Start” メソッド内で起こったことを示しています。このメソッドの実装を注意深く見ると,問題の原因が明らかになるでしょう。一般的に,NullReferenceExceptionsは,Startメソッドの内部で初期化の順序について間違った前提を行った際に起きます。 場合によってはスタックトレースの一部分のみがデバッガコンソールに表示されます。

Thread 1 (thread 11523): 

1. 0 0x0062564c in start ()

これはネイティブのシンボルがアプリケーションのリリースビルドの際に取り除かれたことを示しています。フルスタックトレースは,以下の手順で得ることができます。

  • デバイスからアプリケーションを削除します
  • 全てのターゲットをクリーンアップします
  • ビルドおよび実行します
  • スタックトレースを上記の手順どおりに取得します

外部ライブラリがUnity iOSアプリケーションにリンクされているときEXC_BAD_ACCESSが発生します。

通常,外部ライブラリは,ARM Thumb命令セットでコンパイルされたときに生成されます。現在,このようなライブラリはUnityと互換性がありません。Thumb命令なしでライブラリを再コンパイルすることで簡単に問題を解決することができます。Xcodeプロジェクトのライブラリからは次の手順でのこれを行います:

  • Xcodeでメニューから “View” > “Navigators” > “Show Project Navigator” を選びます
  • “Unity-iPhone” プロジェクトを選択し,“Build Settings” タブを有効に
  • 検索フィールドで “Other C Flags” と入力
  • -mno-thumb フラグをそこに追加してライブラリをリビルド

ライブラリのソースが利用できない場合は,Thumbコードではないライブラリのバージョンをサプライヤーに依頼する必要があります。

Xcodeのコンソールに“WARNING -> applicationDidReceiveMemoryWarning()” 表示され,その後すぐにアプリケーションがクラッシュする

(時には, Program received signal: “0” のようなメッセージが表示される場合があります。) この警告メッセージは,多くの場合,致命的なものではなく,単にiOSのメモリーが少なくなって,アプリケーションにいくつかのメモリを解放するを求めていることを示しています。一般的に,メールのようなバックグラウンドプロセスは,いくつかのメモリを解放し,アプリケーションを実行し続けることができます。ただし,アプリケーションがメモリを引き続き使用,またはそれ以上を求めた場合,iOSは最終的にアプリケーション達とそれらのいずれかを終了させる可能性があります。Appleはメモリ使用量がいくらあれば安全であるかを明文化していませんが,経験からデバイスの全RAM50%未満(第2世代iPadではおよそ200〜256MB)をアプリケーションが使用している場合,メモリ使用量について大きな問題ありません。 注意するべき指標は,アプリケーションがどのくらいのRAM使用するかです。あなたのアプリケーションのメモリ使用サイズは3つの主要なコンポーネントで構成されています。:

  • アプリケーションコード(OSがRAMにアプリケーション·コードをロードし,保持する必要がありますが,実際には必要に応じて一部が廃棄される場合があります)
  • ネイティブヒープ(state,asset等をRAMに保存するためにエンジンによって用意される)
  • マネージヒープ(C#またはJavaScriptオブジェクトを維持するためにあなたのMonoランタイムで使用)
  • GLESドライバメモリプール:テクスチャ,フレームバッファ,コンパイルされたシェーダなど アプリケーションのメモリ使用量はXcode Instruments tools : Activity Monitor,Object AllocationsおよびVM Tracker でトラッキングできます。Xcode Run menu: Product > Profile から実行し,特定のツールを選択します。Activity Monitor ツールで,アプリケーションで使用するRAMの総量とReal memoryを含むすべてのプロセスの統計情報を表示します。 __注意:__ iOSやデバイスのハードウエアバージョンの組み合わせによりメモリ使用量の数値に著しく影響を与える可能性があるため,別のデバイス上で取得した数値を比較する際には注意する必要があります。

注意: 内部プロファイラは,.NETスクリプトによって割り当てられたヒープのみを表示します。総メモリ使用量は,上記のようにXcode Instrumentsを介して決定できます。この図では,アプリケーションバイナリの一部,いくつかの標準フレームワークバッファ,Unityエンジン内部ステートバッファ,.NETランタイムヒープ(内部プロファイラによって表示される番号 ),GLESドライバヒープ,いくつかの他の様々なものを含みます。

他のツールはアプリケーションによって行われた割り当てを全て表示し,ネイティブヒープとマネージドヒープの両方の統計を含みます。(アプリケーションの現在の状態を取得するために,Created and still livingボックスを忘れずにオンにしてください)。重要な統計は,Net bytes値です。

メモリ使用を抑えるために:

iOSの強力なストリッピングオプション(Advancedライセンス機能)を使用してアプリケーションのバイナリサイズを小さくし,異なる.NETライブラリからの不要な依存関係を避けるようにします。詳細については,プレイヤー設定iOSプレイヤーのサイズ最適化のマニュアルページを参照してください。 * コンテンツのサイズを小さくしてください。テクスチャにPVRTC圧縮を使用し,ローポリゴンモデルを使います。詳細については,ファイル サイズの削減のマニュアルページを参照してください。

  • スクリプトで必要以上にメモリを割り当てないでください。Monoのヒープサイズと使用状況をビルトインプロファイラでのパフォーマンス測定で追跡します。
  • 注意: Unity3.0以降,シーンのロードの実装は大幅に変更され,現在はすべてのシーンアセットがプリロードされています。この結果,ゲームオブジェクトをインスタンスする際,乱れることがあります。ゲームプレイ中にアセットのロードとアンロードをよりきめ細かく制御する必要がある場合は,Resources.LoadObject.Destroyを使用してください。

空きメモリの量についてのOSに照会することは,アプリケーションのパフォーマンスを評価するための良いアイデアのように思えるかもしれません。OSはダイナミックバッファとキャッシュを多く使用してるので,空きメモリの統計は信頼できない可能性が高いです。唯一信頼できるアプローチは,アプリケーションのメモリ消費量を追跡し,これを主な指標として使うことです。特に新しいレベルをロードしたとき,上記のツールでどのようにグラフが時間の経過とともに変化するかに注意を払います。

ゲームがXcodeのから起動した時には正しく実行するが,デバイス上で手動で起動すると最初のレベルのロード中にクラッシュします。

これにはいくつかの理由が考えられます。より多く詳細を確認するために,デバイスのログをチェックする必要があります。Macにデバイスを接続し,Xcodeを起動してメニューからWindow > Organizerを選択します。Organizerの左ツールバーで使っているデバイスを選択し,“Console” タブをクリックして慎重に最新のメッセージを確認します。さらにクラッシュレポートを調べる必要があるかもしれません。クラッシュレポートを取得する方法は以下にあります。:http://developer.apple.com/iphone/library/technotes/tn2008/tn2151.html

Xcode Organizer コンソールのメッセージが “killed by SpringBoard”のとき

貧弱なドキュメントにiOSアプリケーションには最初のフレームをレンダリングして入力処理には時間制限があるとあります。アプリケーションがこの制限を超えるとSpringBoardに強制終了されます。これは,例えばアプリケーションの最初のシーンが大きすぎると起こるかもしれません。スプラッシュスクリーンを表示するだけの小さな初期のシーンを作成し,yield で1または2フレーム待ってから,実際のシーンのロードすることをお勧めします。これは次のような簡単なコードで実行できます。:

function Start() {
    yield;
    Application.LoadLevel("Test");
}

Type.GetProperty() / Type.GetValue() がデバイスでクラッシュを引き起こすとき

今のところ,Type.GetProperty()Type.GetValue() は,.NET 2.0 Subset プロファイルでのみサポートされています。Player Settings での.NET APIの互換性レベルを選択することができます。

注:Type.GetProperty()Type.GetValue() は,マネージコードストリッピングと互換性がない可能性があり,除外する必要があるかもしれません(これを達成するためにストリッピング処理中にカスタムの非ストリッピングタイプのリストを提供して除外することができます)。より詳しいことはiOSのプレイヤーサイズの最適化ガイドを参照してください。

ゲームがエラーメッセージ ‘SometType1&lt;SomeValueType&gt;:.ctor ()' "ExecutionEngineException: Attempting to JIT compile method 'SometType1<SomeValueType>:.ctor ()’ while running with –aot-only." と表示されてクラッシュします。

iOS用のMono.NET実装は,AOT(ネイティブコードへahead of time compilation:事前コンパイル)に基づいており,制約があります。それは明示的に他のコードで使用されているジェネリック型のメソッド(バリュータイプがジェネリックパラメータとして使用される場合で)のみをコンパイルします。このような方法がreflectionまたは,ネイティブコード(すなわち,シリアライゼーションシステム)だけを経由して使われている時,AOTコンパイル中にスキップされます。AOTコンパイラは,スクリプトコードのどこかにダミーメソッドを追加することで,コードをincludeすると指示できます。これで足りないメソッドを参照できるので,それらを事前にコンパイルできます。

void _unusedMethod() {
    var tmp = new SomeType<SomeValueType>();
}

注意: バリュータイプは基本的な enumsとstructsです。

System.Security.Cryptography とマネージコードリッピングを使った組み合わせを使用したとき,様々なクラッシュがデバイス上で発生

.NETの暗号化サービスは,reflectionに大きく依存し,これは静的コード分析を伴うため,マネージコードは,ストリッピングと互換性がありません。時々するクラッシュの最も簡単な解決方法は,ストリッピングプロセスから System.Security.Crypography名前空間の全体を取り除くことです。

ストリッピングプロセスは,Unityプロジェクトの Assets フォルダにカスタム link.xml ファイルを追加することでカスタマイズすることができます。これでストリッピングから取り除く型と名前空間を指定します。詳細は iOSプレイヤーのサイズ最適化に記載されています。

link.xml

<linker>
       <assembly fullname="mscorlib">
               <namespace fullname="System.Security.Cryptography" preserve="all"/>
       </assembly>
</linker>

マネージコードストリッピングでSystem.Security.Cryptography.MD5を使ってアプリケーションがクラッシュする

上記のアドバイスを検討するか,スクリプトコード,特定のクラスに,参照を追加することでこの問題を回避できるかもしれません。

object obj = new MD5CryptoServiceProvider();

“Ran out of trampolines of type 0/1/2” ランタイムエラー

通常,再帰的なジェネリックを多く使用する場合に,このエラーは発生します。より多くのtype0,type1,type2 トランポリンを割り当てるようAOTコンパイラへ指示できます。追加のAOTコンパイラのコマンドラインオプションは プレイヤー設定の “Other Settings” セクションで指定できます。type 1トランポリンの場合,nrgctx-trampolines=ABCD を指定,つまりABCDが必要な新しいトランポリンの数(すなわち4096)を指定します。type2トランポリンは nimt-trampolines=ABCD を指定し,type0トランポリンは ntrampolines=ABCDを指定します。

Xcodeをアップデートした後,Unity iOS ランタイム実行失敗時,次のメッセージがでる。“You are using Unity iPhone Basic. You are not allowed to remove the Unity splash screen from your game.(あなたはUnity iPhone Basicを使用しています。あなたのゲームから Unity スプラッシュ画面を削除することはできません)”

いくつかの最新のXcodeリリースでPNG圧縮と最適化ツールを導入した変更がありました。これらの変更は,スプラッシュスクリーン変更時,UnityのiOS実行時チェックで誤った判定の原因となります。このような問題が発生した場合は,Unityを最新の公開された利用可能なバージョンにアップグレードしてみてください。このような問題が発生した場合は,Unityを最新の公開された利用可能なバージョンにアップグレードしてみてください。それで解決しない場合は,以下の回避策を考慮してください。

  • Unityからビルドするとき(それを追加するのではなく)Xcodeプロジェクトをスクラッチから作ってビルドしてください。

  • 既にデバイスにインストールされているプロジェクトを削除します。

  • Xcodeでプロジェクトをクリーンします。 (Product->Clean)

  • XcodeのDerived Data folderをクリアします。 (Xcode->Preferences->Locations) これでもまだ解決しない場合はXcodeでPNGの再圧縮を無効にしてみてください:

  • Xcodeプロジェクトを開きます。

  • そこで“Unity-iPhone” プロジェクトを選択します。

  • そこで“Build Settings”タブを選択します。

  • “Compress PNG files”を見つけて,NOにセットします。

App Storeへの提出が失敗する。メッセージは“iPhone/iPod Touch: application executable is missing a required architecture. At least one of the following architecture(s) must be present: armv6 (アプリケーション実行可能ファイルに必要なアーキテクチャではありません。少なくとも以下のアーキテクチャ必要が必要です。:armv6)”

以前armv6サポートを受けて提出された既存のアプリケーションを更新するときには,そのようなメッセージが表示されることがあます。Unity4.xとXcodeの4.5はarmv6のプラットフォームをもうサポートしていません。提出問題を解決するために,Unity Player SettingsTarget OS Version4.3以上に設定します。

WWWのダウンロードがUnity EditorでとAndroid上では正常に動作しますが,iOS上ではうまくいきません。

よくある間違いは,WWWのダウンロードが常に別のスレッドで起きていることを前提にしていることです。一部のプラットフォームでは正しいかもしれませんが,当たり前のこととするべきではありません。WWWの状態を追跡するための最良の方法は, yield ステートメントを使用するか,または Update メソッド でステータスをチェックするかのどちらかです。 while ループはビジーになるため。使うのは no です。

スクリプトからコールしたネイティブ関数を経由してCocoaを使用した際に“PlayerLoop called recursively!(PlayerLoopが再帰的に呼ばれてます!)” エラーが発生する

UIのいくつかの操作はiOSがすぐにウィンドウを再描画させます(最も一般的な例は,メインのUIWindow へ UIViewControllerとUIViewを追加する場合です)。スクリプトからネイティブ関数を呼び出した場合,それはUnityのPlayerLoop内部で発生し,結果的にPlayerLoopで再帰的に呼び出されることになります。その場合,waitUntilDoneをfalseに設定し,performSelectorOnMainThreadメソッドの使用を検討する必要があります。UnityのPlayerLoopの呼び出しの間に実行する処理のスケジュールをiOSに通知します。

プロファイラやデバッガでiOSデバイス上でゲームの動作を見ることができない

  • 開発ビルドを構築していることを確認し,(必要に応じて)“Enable Script Debugging”と“Autoconnect profiler”ボックスを設定してください。
  • デバイス上で動作するアプリケーションは,225.0.0.222のUDPポート54997にmulticast/broadcastを行います。お使いのネットワーク設定がこのトラフィックを許可していることを確認してください。その後,プロファイラはデバイスからプロファイラデータをフェッチするポート番号55000から55511の範囲のリモートデバイスに接続を行います。これらのポートはUDPアクセスのために開いておく必要があります。

DDLが見つからない

アプリケーションはエディタ上では実行が[OK]なのですが,iOSプロジェクトでエラーが出る場合,行方不明のDLL(例 I18N.dll, I19N.West.dll)によって引き起こされているかもしれません。この場合,それらのDLLをUnity.app内からプロジェクトのAssets/Plugins フォルダにコピーしてみてください。Unityアプリケーション内のDLLの場所は次のとおりです。: Unity.app/Contents/Frameworks/Mono/lib/mono/unity その後,ビルドが最適化されたとき,DLLクラスが削除されていないことを確認するために,プロジェクトのストリッピングレベルをチェックする必要があります。iOS ストリッピングレベルの詳細については,iOS Optimisation Pageを参照してください。

Xcode デバッガ コンソール出力 : ExecutionEngineException: Attempting to JIT compile method ‘(wrapper native-to-managed) Test:TestFunc (int)’ while running with –aot-only

通常,このようなメッセージは,マネージドファンクションデリゲートがネイティブファンクションに渡し,アプリケーションを構築時,必要なラッパーコードが生成されなかった場合に受信されます。どのメソッドがネイティブコードにデリゲートとして渡すかをAOTコンパイラに指示し,助けることができます。これは,カスタム属性“MonoPInvokeCallbackAttribute”を追加することで行うことができます。現在,静的メソッドのみをネイティブコードにデリゲートとして渡すことができます。

サンプルコード:

using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
using AOT;

public class NewBehaviourScript : MonoBehaviour {
    [DllImport ("__Internal")]
    private static extern void DoSomething (NoParamDelegate del1, StringParamDelegate del2);

    delegate void NoParamDelegate ();
    delegate void StringParamDelegate (string str);
    
    [MonoPInvokeCallback(typeof(NoParamDelegate))]
    public static void NoParamCallback() {
        Debug.Log ("Hello from NoParamCallback");
    }
    
    [MonoPInvokeCallback(typeof(StringParamDelegate))]
    public static void StringParamCallback(string str) {
        Debug.Log(string.Format("Hello from StringParamCallback {0}", str));
    }

    // Use this for initialization
    void Start() {
        DoSomething(NoParamCallback, StringParamCallback);
    }
}

Xcodeが以下のコンパイルエラー(メッセージを)を投げてきた: “ld : unable to insert branch island. No insertion point available. for architecture armv7”,

“clang: error: linker command failed with exit code 1 (use -v to see invocation)”

そのエラーは,通常,単一のモジュール内にあまりにも多くのコードがあることを意味します。一般的には多くのスクリプトコードがあるか,大きな外部.NETアセンブリがビルドに含めることによって引き起こされます。そして,スクリプトのデバッグを有効にすると,各ファンクションにかなりの数の命令が追加されるため,事態を悪化させるかもしれず,それは制限した方が容易になります。

この問題解決のためにplayer settings でマネージドコードストリッピングを有効にすると役に立つかもしれません。特に,大きな外部.NETアセンブリが関与している場合は。しかし,問題が続く場合の最善の解決策は,ユーザのスクリプトコードを複数のアセンブリに分割することです。このための最も簡単な方法は,Pluginsフォルダにいくつかのコードを移動することです。この場所にあるコードは,別のアセンブリに配置されます。また,スクリプトのコンパイルにどのように影響するかを,special folder namesについて情報を確認してください。

Unity iOS が現在サポートしていない機能
iOSでのクラッシュ時バグレポート方法 / Reporting crash bugs on iOS