読者です 読者をやめる 読者になる 読者になる

【何回かに分けて更新予定】(3) Android StudioでUnity向けにmoduleを作るときのトラブル対応集

Unity Android

前回と前々回で、Android nativeの関数をUnityから呼び出す方法について紹介してきました。

magicbullet.hatenablog.jp

magicbullet.hatenablog.jp

この方法によりJavaで書いたコードをUnityで呼べるのは間違いありません。

しかし、2回目で書いたように、実際に呼びたいAndroidの側のコードはもっと複雑であることが多く、この方法だけではうまくいかないことがあります。

たとえば、下記の記事で試している音声認識ソースコード(Android Studio)をUnityで使おうとすると、色々なエラーがでてしまい、使うことができません。

magicbullet.hatenablog.jp



そこで、この記事では、AndroidのnativeコードをUnityで使うとき、私が困ったことと対応方法について整理したいと思います。

そこそこ多くなりそうなので、何回かに分けて追加していきます。

===

トラブル対応集の一覧

(1) Android StudioでUnity系のpackageを書くとエラーになる。

(2) manifest.srcFileを書くと、AndroidManifest.xmlがない、というエラーが出る。

(3) aarとjarは、どちらを使えばよいか?

(4) Unityでビルドすると、Error building Player: IOException: Failed to Move File / Directory from 'aaa' to 'bob' というエラーがでる。(2016/11/1追加)

(5) activityを呼び出すには?(2016/11/28に追加)

(6) activityを呼び出すコードをtypoなく書いたのに、java.lang.ClassNotFoundExceptionが出る。(2016/12に追加予定)

(7) AndroidプロジェクトにC/C++ネイティブライブラリを含むとき、Unityではどこに配置するか? (2016/12に追加予定)

(8) Serviceを使うと、 android.os.BinderProxy cannot be cast to aaa というエラーが出る。(2016/12に追加予定)

(9) Unityで現在のAcitivityを取得するには? (2016/12に追加予定)

===

(1) Android StudioでUnity系のpackageを書くとエラーになる。

たとえば、Unityの関数(例:UnitySendMessage)をAndroidから呼び出したり、Unity上のAndroid向けActivityを取得するためには、下記のようなpackageをインポートする必要があります。

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
import com.unity3d.player.UnityPlayerNativeActivity;

これをソースコードに書くとエラーになります。回避するには、Unityアプリケーションの中にあるclasses.jarをAndroid Studioのプロジェクトにインポートする必要があります。

classes.jarはMacWindowsで置き場所が異なります。下記はUnity5.3.5f1のときの配置です。Unityのバージョンによって場所が変わることがあるようなのでご注意ください。

Macの場合

/アプリケーション/Unity/PlaybackEngine/AndroidPlayer/Variations/mono/Release/Classes/classes.jar

Windowsの場合

C:\Program Files\Unity\Editor\Data/PlaybackEngines/AndroidPlayer/Varitations/mono/Release/Classes/classes.jar

インポートする場所は下記です。

f:id:Takyu:20161023200003p:plain

Warningなどが1,2回出ますが、OKを押して進めます。

この後、gradleのsyncを実行すればエラーが消えます。

f:id:Takyu:20161023200927p:plain

(2) manifest.srcFileを書くと、AndroidManifest.xmlがない、というエラーが出る。

build.gradleには、srcやAssetsフォルダなどを認識させるためのオプション "sourceSets"があります。

下記のブログを書かれた方の動機から推測すると、このオプションはEclipse上での構成を移行するときに使うようです。

qiita.com


今回、MicrosoftのBingSpeechAPIをmodule化するために、新規プロジェクトを作って試したりもしました。

そのとき、元のMSのサンプルコードにあるbuild.gradleを書き写したところ、下記でエラーになりました。

android{
(途中省略)
    sourceSets {
        main {
         manifest.srcFile 'AndroidManifest.xml'
(途中省略)
        }
}

Error:A problem was found with the configuration of task ':app:checkDebugManifest'.
> File '/Users/UserName/AndroidStudioProjects/Test/app/AndroidManifest.xml' specified for property 'manifest' does not exist.


また、Android Viewからはmanifestフォルダが消えてしまいました。

f:id:Takyu:20161023202818p:plain



原因は、自分で作ったAndroid StudioプロジェクトとEclipseから移行したプロジェクトではManifestファイルの配置場所が異なっているためです。

Android Studio(2.1.2)で作った場合

app/src/main/AndroidManifest.xml

Eclipseから移行した場合

app/AndroidManifest.xml


十分には確認していないのですが、今回のオプションは Eclipseから移行したプロジェクトでなければ不要です。

ちなみに、build.gradleで manifest.srcFile 'AndroidManifest.xml'のオプションを削除すると、Android ViewでmanifestフォルダとAndroidManifest.xmlが復活します。

f:id:Takyu:20161023203739p:plain

(3) aarとjarは、どちらを使えばよいか?

UnityでAndroidのコードを使うには、aarかjarのどちらかをインポートする必要があります。

aarとjarの違いはここで解説した通りで、

aar : Android Archive Library (Androidアプリ開発に必要なファイルをまとめたもの)

jar : Java Archive

です。

つまり、aarの方が範囲が広く、aarにはjarだけでなくAndroidManifest.xmlも入っています。


自分の実験結果、および購入したアセットのフォルダ構成調査の結果から、Unityではaarもjarのどちらも使えます。
(Plugins/Androidに入れるだけです)

しかし、aarを使う場合、Androidmanifest.xmlの記述内容によっては、Unityでビルドした時にコンフリクトエラーになる場合があるため、Unityで準備されているAndroidManifest.xmlと重複記述がないようにする必要があります。

Unityで準備されているAndroidManifest.xmlは、MacWindowsで置き場所が異なります。

Macの場合

/アプリケーション/Unity/PlaybackEngine/AndroidPlayer/Apk/AndroidManifest.xml

Windowsの場合

C:\Program Files\Unity\Editor\Data/PlaybackEngines/AndroidPlayer/Apk/AndroidManifest.xml

中身はこうなっています。


gistb991ce1d94b5cdf556bafc7b88a8ae61


たとえば、Activityでintent.Action.MAINをAndroid Studio側に書いてしまうと、Unity側とコンフリクトを起こすので、書かないようにします。

(4) Unityでビルドすると、Error building Player: IOException: Failed to Move File / Directory from 'aaa/classes.jar' to 'bob/classes.jar' というエラーがでる。(2016/11/1追加)

jarファイルだけを使う場合、このエラーは発生しません。

これはAndroid StudioでUnitySendMessageとか、Unity向けのメソッドを使うために入れたclasses.jarが、Unityに入れたaarに残っており、UnityでAndroid向けのビルドをするときに使われるclasses.jarとかぶってしまうのが原因のようです。

starzero.hatenablog.com



解決するには、Android Studio側のbuild.gradleで下記を書いておきます。

android.libraryVariants.all { variant ->
    variant.outputs.each { output ->
        output.packageLibrary.exclude('libs/classes.jar')
    }
}

この記述により、Android Studioでライブラリのパッケージ(aar)を作る時、libs/classes.jarを除きます。

(5) activityを呼び出すには?(2016/11/28に追加)


aarの中にActivityがある場合、Unityから呼び出すことができます。

それぞれ、下記のコードを書きます。Java側のAcitivityに画面を準備していない場合、startActivityを呼び出した段階で画面が真っ白になります。


Android Studio

//import宣言などは省略

public void launchActivity(final Activity m_activity){
    Intent i = new Intent();
    i.setClassName(m_activity,"よびだしたいactivityをpackage名を含むフルパスで表記");
    i.setAction(Intent.ACTION_MAIN);
    m_activity.startActivity(i);
}

Unity側

//using宣言などは省略

public void launchActivity(){
  AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  AndroidJavaObject currentUnityActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
  AndroidJavaClass plugin = new AndroidJavaClass("Java側で呼び出したいActivityを持つクラスを、package名を含むフルパスで表記");
  plugin.CallStatic("launchActivity",currentUnityActivity);  // 第一引数は、Java側のメソッド名
}

また次の機会に更新します。