前回UnityでSwiftで書いたiOSのネイティブコードを使う方法について記載しました。
(実際やってみるとUnityでビルドする度にXcode上の設定が戻ってしまって辛い問題が...)
その後Androidのネイティブコードも書いてみてiOSとAndroidのプロジェクト構成に違いが出たなぁということでメモ書きです。
Bariiiii Assets、ProjectSettingsは Unityプロジェクトで使用されるものです。
iOS 一旦Xcodeのプロジェクトが作成されて Xcode経由でiOS端末にアプリインストールします。
Android Unityの設定でAndroid SDKのパス設定が正常ならば Unityのビルドで直接Android端末にアプリインストールします。
Layout XML、コードなどはよくあるAndroidプロジェクトの配置と同じです。
使用したいAndroidプロジェクトのActivityや必要な権限(permission)はUnityプロジェクト側のAndroidManifest.xmlに記載します。 理由としてはUnityビルド中に他のaarファイルの中にあるAndroidManifest.xmlがマージを行いコンフリクトを起こす原因になるからです。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="work.syonet.bariiiii">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
</manifest>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.INTERNET" />
<application
android:theme="@style/UnityThemeSelector"
android:icon="@drawable/app_icon"
android:label="@string/app_name">
<activity
android:name="com.unity3d.player.UnityPlayerNativeActivity"
android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
<meta-data android:name="android.app.lib_name" android:value="unity" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="work.syonet.bariiiii.BarcodeScanAndroidActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation"
android:exported="true"
android:permission="android.permission.INTERNET">
</activity>
</application>
</manifest>
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.0.3'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ちょっとkotlin使いたかったのでその設定ぐらいしかしていません
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 23
buildToolsVersion "24.0.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
}
// UnityのAndroidプラグインフォルダに移動させる
task copyLibs << {
configurations.compile.each { lib ->
if (lib.path.startsWith("${projectDir}/libs")) {
// libs内のものはコピー対象外
return
}
copy {
from lib.path
into '../../Assets/Plugins/Android'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'com.google.android.gms:play-services-vision:9.4.0'
// Unityのプラグイン一覧には含めない
provided files('/Applications/Unity/PlaybackEngines/AndroidPlayer/Variations/mono/Development/Classes/classes.jar')
}
// このプロジェクトをaar化させる
task exportAar(type: Copy, dependsOn: assembleRelease) {
from('build/outputs/aar/')
into('../../Assets/Plugins/Android/')
include('app-release.aar')
rename('app-release.aar', 'bariiiii.aar')
}
android.libraryVariants.all { variant ->
variant.outputs.each { output ->
output.packageLibrary.exclude('libs/classes.jar')
}
}
このbuild.gradleファイルで注目する点として
gradlew app:copyLibs && gradlew app:exportAar
build.gradlewやAndroidManifest.xml、UnityEditor上で指定されているminSdkVersionやtargetSdkVersionはバラツキがないように設定
ここのやり方は公式や他のQiitaの記事でも書いてあったりしますので詳しい説明は割愛します。 ActivityLauncher.javaというkotlinじゃなくてJavaのファイルにした理由ですが特にありません。 強いて理由とすればC#とJavaって書き方似てるなぁという愉悦に浸るぐらいの程度のものです。
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentUnityActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaClass plugin = new AndroidJavaClass("work.syonet.bariiiii.ActivityLauncher");
plugin.CallStatic("launchActivity", "work.syonet.bariiiii.BarcodeScanAndroidActivity", currentUnityActivity );
package work.syonet.bariiiii;
import android.app.Activity;
import android.content.Intent;
/**
* C#のコードからAndroidのアクティビティにつなげるクラス
*/
public class ActivityLauncher {
/**
* AndroidのアクティビティにIntentを発行する
* @param type 起動したいアクティビティ
* @param m_activity Unity自身のアクティビティ
*/
public static void launchActivity(String type, final Activity m_activity) {
Intent i = new Intent();
i.setAction(Intent.ACTION_MAIN);
i.setClassName(m_activity, type);
// 画面遷移を行う
m_activity.startActivity(i);
}
}
この記事の冒頭にもありましたが/Assets/Plugins/iOS/下に配置します。
このプロジェクトはXcodeで作成されますが、
対象のネイティブコードはUnity管理のディレクトリ/Assets/Plugins/iOS/に直接配置します。この構成を実現させるにはXcodeプロジェクト上のファイルと実ファイルの参照がちゃんとリンクさせる必要があります。
iOSにもLayoutを構成するxibファイルやstoryboardなどInterface Builderで作成したもの達がありますがUnity上でも呼び出すことが可能で特別なIBの設定なども必要ありません。
まず/Assets/Plugins/iOS/下に空のクラスファイルを作成します。 あとはFinderからファイルをXcode上にドラッグアンドドロップしましょう。
これでリンクされるようになります。
ここのやり方もAndroid同様に公式や他のQiitaの記事でも書いてあったりしますので詳しい説明は割愛です。
[DllImport("__Internal")]
private static extern void barcordScanInit_ ();
public static void barcordScanInit () {
if (Application.platform != RuntimePlatform.OSXEditor) {
barcordScanInit_ ();
}
}
#pragma mark called by C#
/**
* MARK:Unity上で扱うViewController
*/
extern UIViewController *UnityGetGLViewController();
extern "C" {
void barcordScanInit_();
}
/**
* MARK:C#からBarcodeIOSのクラスを呼び出す
*/
void barcordScanInit_() {
UINib *nib = [UINib nibWithNibName:@"BarcodeScanIOSScreen" bundle:nil];
BarcodeScanIOS *barcode = [[nib instantiateWithOwner:nil options:nil] objectAtIndex:0];
[UnityGetGLViewController() presentViewController:barcode animated:YES completion:nil];
}
Unityプロジェクトとネイティブコードプロジェクトのビルドを楽にできるようなツールを作成中 https://github.com/igara/Bariiiii/tree/master/BuildTool もっとiOSのビルドが楽になるようなものを作っていきたいです。