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

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

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

ゲームがしばらくして応答を停止し、Xcode がステータスバーに interrupted (中断) と表示する

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

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

Xcode コンソールに「Program received signal SIGBUS」または「EXC_BAD_ACCESS」エラーが表示される

This message typically appears on iOS devices when your application receives a NullReferenceException. There are two ways to figure out where the fault happened:

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

Unity includes software-based handling of the NullReferenceException. The AOT compiler includes quick checks for null references each time a method or variable is accessed on an object. This feature affects script performance, which is why it is enabled only for development builds (enable the script debugging option in Build Settings dialog). If everything was done right and the fault actually is occurring in .NET code then you won’t see EXC_BAD_ACCESS anymore. Instead, the .NET exception text will be printed in the Xcode console (or else your code will just handle it in a “catch” statement). Typical output might be:

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

This indicates that the fault happened in the handleTimeOfDay method of the DayController class, which works as a coroutine. Also, if it is script code then you will generally be told the exact line number (e.g. “DayController.js:122”). The offending line might be something like the following:

 Instantiate(_imgwww.assetBundle.mainAsset);

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

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

Native stack traces are a much more powerful tool for fault investigation but using them requires some expertise. Also, you generally can’t continue after these native (hardware memory access) faults happen. To get a native stack trace, type bt all into the Xcode Debugger Console. Carefully inspect the printed stack traces; they may contain hints about where the error occurred. You might see something like:

...
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 ()
...

Firstly, you should find the stack trace for “Thread 1”, which is the main thread. The very first lines of the stack trace will point to the place where the error occurred. In this example, the trace indicates that the NullReferenceException happened inside the OptionsMenu script’s Start method. Looking carefully at this method implementation would reveal the cause of the problem. Typically, NullReferenceExceptions happen inside the Start method when incorrect assumptions are made about initialization order. In some cases only a partial stack trace is seen on the Debugger Console:

Thread 1 (thread 11523): 

1. 0 0x0062564c in start ()

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

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

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

This usually happens when an external library is compiled with the ARM Thumb instruction set. Currently, such libraries are not compatible with Unity. The problem can be solved easily by recompiling the library without Thumb instructions. You can do this for the library’s Xcode project with the following steps:

  • In Xcode, select View > Navigators > Show Project Navigator from the menu
  • Select the Unity-iPhone project, activate Build Settings tab
  • In the search field enter: Other C Flags
  • Add -mno-thumb flag there and rebuild the library.

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

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

Sometimes, you might see a message like Program received signal: “0”. This warning message is often not fatal and merely indicates that iOS is low on memory and is asking applications to free up some memory. Typically, background processes like Mail will free some memory and your application can continue to run. However, if your application continues to use memory or ask for more, the OS will eventually start killing applications and yours could be one of them. Apple does not document what memory usage is safe, but empirical observations show that applications using less than 50% of all device RAM do not have major memory usage problems. The main metric you should rely on is how much RAM your application uses. Your application memory usage consists of three major components:

  • Application code (the OS needs to load and keep your application code in RAM, but some of it might be discarded if really needed)
  • Native heap (used by the engine to store its state, your assets, etc. in RAM)
  • Managed heap (used by your Mono runtime to keep C# objects)
  • GLES driver memory pools: textures, framebuffers, compiled shaders, etc. Your application memory usage can be tracked by two Xcode Instruments tools: Activity Monitor and Allocations. You can start from the Xcode Run menu: Product > Profile and then select specific tool or via Xcode > Open Developer Tools > Instruments. Activity Monitor tool shows all process statistics including Real memory which can be regarded as the total amount of RAM used by your application. Note: OS and device HW version combination might noticeably affect memory usage numbers, so you should be careful when comparing numbers obtained on different devices.

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

The other tool displays all allocations made by your application and includes both native heap and managed heap statistics. The important statistic is the Net bytes value.

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

  • Reduce the application binary size by using the strongest iOS stripping options, and avoid unnecessary dependencies on different .NET libraries. See the Player settings and Optimizing the size of the built iOS Player for further details.
  • コンテンツのサイズを小さくしてください。テクスチャに PVRTC 圧縮を使用し、ローポリゴンモデルを使います。詳細については、ファイルサイズの削減のマニュアルページを参照してください。
  • Don’t allocate more memory than necessary in your scripts. Track mono heap size and usage with the internal profiler.

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

ゲームが Xcode から起動したときには正しく実行するが、デバイス上で手動で起動すると最初のレベルの読み込み中にクラッシュする

There could be several reasons for this. You need to inspect the device logs to get more details. Connect the device to your Mac, launch Xcode and select Window > Devices and Simulators from the menu. Select your device in the window’s left toolbar, then click on the Show the device console button and review the latest messages carefully. Additionally, you may need to investigate crash reports. You can find out how to obtain crash reports here: http://developer.apple.com/iphone/library/technotes/tn2008/tn2151.html.

Xcode Organizer コンソールのメッセージに「killed by SpringBoard」が含まれる

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

IEnumerator Start() {
    yield return new WaitForEndOfFrame();
// Do not forget using UnityEngine.SceneManagement directive
    SceneManager.LoadScene("Test");
}

Type.GetProperty() or Type.GetValue() cause crashes on the device

Currently Type.GetProperty() and Type.GetValue() are supported only for the .NET 2.0 Subset profile. You can select the .NET API compatibility level in the Player settings.

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

ゲームがエラーメッセージ 「ExecutionEngineException: Attempting to JIT compile method ‘SometType`1<SomeValueType>:.ctor ()’ while running with –aot-only.」 を表示してクラッシュする

The Mono .NET implementation for iOS is based on AOT (ahead of time compilation to native code) technology, which has its limitations. It compiles only those generic type methods (where a value type is used as a generic parameter) which are explicitly used by other code. When such methods are used only via reflection or from native code (i.e. the serialization system) then they get skipped during AOT compilation. The AOT compiler can be hinted to include code by adding a dummy method somewhere in the script code. This can refer to the missing methods and so get them compiled ahead of time.

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

Note: Value types are basic types, enums and structs.

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

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

The stripping process can be customized by adding a custom link.xml file to the Assets folder of your Unity project. This specifies which types and namespaces should be excluded from stripping. Further details can be found in the iOS player size optimization guide.

link.xml

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

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

You should consider the above advice or try working around this problem by adding extra references to specific classes to your script code:

object obj = new MD5CryptoServiceProvider();

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

This error usually happens if you use lots of recursive generics. You can hint to the AOT compiler to allocate more trampolines of type 0, type 1 or type 2. Additional AOT compiler command line options can be specified in the Other Settings section of the Player settings. For for type 0 trampolines specify ntrampolines=ABCD, where ABCD is the number of new trampolines required (i.e. 4096). For type 1 trampolines specify nrgctx-trampolines=ABCD and for type 2 trampolines specify nimt-trampolines=ABCD.

After upgrading Xcode Unity iOS, runtime fails with message “You are using Unity iPhone Basic. You are not allowed to remove the Unity splash screen from your game”

With some latest Xcode releases there were changes introduced in PNG compression and optimization tool. These changes might cause false positives in Unity iOS runtime checks for splash screen modifications. If you encounter such problems try upgrading Unity to the latest publicly available version. If this does not help, you might consider the following workaround:

  • Unity からビルドするとき(それを追加するのではなく) Xcode プロジェクトをスクラッチから作ってビルドします。
  • Delete already installed projects from device
  • Clean project in Xcode (Product > Clean)
  • Clear Xcode’s Derived Data folders (Xcode > Preferences > Locations)

これでもまだ解決しない場合は Xcode で PNG の再圧縮を無効にしてみてください。

  • Xcode プロジェクトを開きます。
  • Select Unity-iPhone project
  • Select Build Settings tab
  • Look for Compress PNG files option and set to NO

WWW のダウンロードが Unity Editor と Android 上では正常に動作するが、iOS 上ではうまくいかない

The most common mistake is to assume that WWW downloads are always happening on a separate thread. On some platforms this might be true, but you should not take it for granted. Best way to track WWW status is either to use the yield statement or check status in Update method. You should not use busy while loops for that.

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

Some operations with the UI will result in iOS redrawing the window immediately (the most common example is adding a UIView with a UIViewController to the main UIWindow). If you call a native function from a script, it will happen inside Unity’s PlayerLoop, resulting in PlayerLoop being called recursively. In such cases, you should consider using the performSelectorOnMainThread method with waitUntilDone set to false. It will inform iOS to schedule the operation to run between Unity’s PlayerLoop calls.

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

  • Check that you have built a Development build, and checked the Script Debugging and Autoconnect Profiler boxes (as appropriate).
  • デバイス上で動作するアプリケーションは、225.0.0.222 の UDP ポート 54997 に multicast/broadcast を行います。お使いのネットワーク設定がこのトラフィックを許可していることを確認してださい。その後、プロファイラーはデバイスからプロファイラーデータをフェッチするポート番号 55000 から 55511 の範囲リモートデバイスに接続を行います。これらのポートは UDP アクセスのために開いておく必要があります。

DLL が見つからない

If your application runs ok in editor but you get errors in your iOS project this may be caused by missing DLLs (e.g. I18N.dll, I19N.West.dll). In this case, try copying those dlls from within the Unity.app to your project’s Assets\Plugins folder. The location of the DLLs within the unity app is: Unity.app\Contents\Frameworks\Mono\lib\mono\unity You should then also check the stripping level of your project to ensure the classes in the DLLs aren’t being removed when the build is optimised. Refer to the iOS Optimisation Page for more information on iOS Stripping Levels.

–aot-only で実行するときに、Xcode デバッガーコンソールが以下を出力する: ExecutionEngineException: Attempting to JIT compile method ‘(wrapper native-to-managed) Test:TestFunc (int)’

Typically, such a message is received when the managed function delegate is passed to the native function, but the required wrapper code wasn’t generated when the application was built. You can help AOT compiler by hinting which methods will be passed as delegates to the native code. This can be done by adding the MonoPInvokeCallbackAttribute custom attribute. Currently, only static methods can be passed as delegates to the native code.

コード例

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));
    }

    // 初期化に使用
    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)」

This error usually means there is just too much code in single module. Typically, it is caused by having lots of script code or having big external .NET assemblies included into build. And enabling script debugging might make things worse, because it adds quite few additional instructions to each function, so it is easier to hit that limit.

Enabling managed code stripping in Player settings might help with this problem, especially if big external .NET assemblies are involved. But if the issue persists then the best solution is to split user script code into multiple assemblies. The easiest way to this is move some code to Plugins folder. Code at this location is put to a different assembly. Also, check the information about how special folder names affect script compilation.


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