ついにUnityを研究し始めました。パーソナル版でもiOS版書き出しができるので、早速iOSがらみの部分をちょっと試してみました。
Xcodeで作った他の自前アプリとこのUnityで作るiOSアプリ間で「キーチェインを介して情報共有できないものか」を試してみました。例えば、既存のiOSアプリでユーザにログインしてもらい、そのセッション情報などをキーチェインに保管し、Unityアプリを起動した時にその情報があれば、改めてログインしてもらわなくてもいいような仕組みを考えています。まだ研究し始めたばかりなので、ここに書くことがベストな方法かわかりませんが、MEMOとして残しておきました。
Unityプロジェクトを作成し、プラグインフォルダを準備
Unityプロジェクトを最初から作るところからスクリーンショットを並べてMEMOしていきます。「UnitySSKeyChain」というプロジェクト名にしました。
立方体を一個なんとなく置いておきます。
このシーンは保存されていないようなので保存しちゃいます。
「TopScene」と名付けてそのままAssetsフォルダ直下に保存しました。
では早速ですが、iOS用のプラグインを用意していきます。UnityのiOSアプリ用の出力は、指定した場所にXcodeのプロジェクト(Objective-C)を書き出します。それは出力後にXcodeで開いて編集するようなこともできるものです。そのXcodeプロジェクトに必要なモジュールをUnityのPluginsフォルダに組み込んでおけばいろいろなモジュールをUnityで扱うことができるようです。
このAssetsフォルダ以下に「Assets/Plugins/iOS/」というようにフォルダを作って、ネイティブ側とやりとりするコードやネイティブ側で利用するモジュールなどを入れて、出力後のXcodeで利用するように準備します。
この辺のことは、
- [Unity マニュアル] iOS 用のプラグインをビルド
- UnityでiOSのネイティブコードを呼び出す最も簡単でシンプルな方法 C# → Objective-C
- [Unity][iOS]Unityからネイティブコードを操作する方法
あたりを参考にさせていただきました。特にUnityマニュアルにはサンプルがあり、だいぶいろいろと試して慣れてきてからくらいに、このサンプルを見るといいと思います。
今回は、出力後のXcodeプロジェクトで「SSKeyChain」(別に他のものでも自前のコードでもいいのですが)を使って、キーチェイン情報をやりとりしようということを試みています。
出力後のコードは、再度Unityで編集を行ったりした場合に、何度も上書きで出力しなおされていくことになると思います。出力の際に「Replace(入れ替え)」するか「Append(追加)」するか聞かれますが、今の所、ほとんど「入れ替え」を選んで書き出し直しています。このため、出力した後のXcodeになんらかの手を加えることは、極力避けていきたいし、CocoaPodsのような仕組みを使ってモジュールを組み込んだりということもしない感じです。なので、ここは、上記のGitHubから「ダウンロード」して手動でファイルをコピーして組み込みます。
Assetsフォルダ以下に「Assets/Plugins/iOS/SSKeychain/」となるようにフォルダを作って階層を作りました。そこにダウンロードしてきたものをコピーしようと思います。
「Reveal in Finder」を選んでそのフォルダをファインダーで開きます。
ダウンロードしたSSKeyChainはXcodeプロジェクトですが、その中で必要なモジュール部分のみをUnityのAssets以下にコピーします。これはモジュールによっていろいろですが、SSKeyChainの場合は以下の4つでよさそうです。
- SSKeychain.h
- SSKeychain.m
- SSKeychainQuery.h
- SSKeychainQuery.m
ネイティブコードとやりとりするスクリプトファイルを準備(NativePlugin.csとNativePlugin.mm)
がとてもシンプルでわかりやすかったです。まずは、Unityの通常のスクリプトファイルから呼び出されるC#スクリプトを用意します。「Assets/iOS」フォルダでコンテキストメニューを開き、「Create>C# Script」でファイルを用意します。名前はなんでもいいと思いますが、こちらのサイトと同じように「NativePlugin」にしておきます(実際のファイル名は「NativePlugin.cs」となっています)。
次にObjective-Cのネイティブコードを用意します。テキストファイルならなんでもいいと思いますが、ここは律儀にXcodeで「.m」ファイルを用意しておきます。
ファイル名は、現段階では「NativePlugin.m」となっています。
拡張子を「.mm」に変更します。こんなアラートが出ますが、そのまま「.mm」で。
それでは、それぞれのスクリプトファイルにコードを書いていきます。コードが呼び出される流れとしては、まずJavascript(あるいはC#)といったUnityのスクリプトから「NativePlugin.cs」が呼び出され、このコードは介すだけでそのまま「NativePlugin.mm」のメソッドを呼び出します。
まずはその通過するだけに過ぎない「NativePlugin.cs」のコードを用意します。
MonoDevelopというコードエディタが起動して以下のようなコードがデフォルトで書かれています。
が、全部削除して、以下のようなコードにします。
Unityのコードから「hoge()」が呼び出されたら、そのままネイティブコードの「hoge_()」を呼び出してその戻り値を返しているだけとなっています。hogehogeの方は、引数をつけて戻り値のない例になっています。
次に「NativePlugin.mm」の方です。
エディタとしてXcodeが開くと思いますが、ここはエディタとして使うだけで、以下のコードを設定します。デフォルトで書かれているものはすべて削除して、
以下のコードを書き込みます。extern “C”で「hote_() 」と「hogehoge_(const char* info)」を定義しておきます。(ここに引数も書いておかないと、不明なエラーで2日間くらい悩んだりします)
「MakeStringCopy」という関数は、Unityマニュアルのサンプルで使われていたもので、キーチェインから取り出したNSString型の文字列をchar型で返す際に使うものになっています。サンプルからまるまるコピーしてきました。この型変換が結構厄介ですね。
も参考にさせていただきました。
hoge_()やhogehoge_()が呼ばれたら、SSkeyChainの利用してデータを保管したり(hogeの方)、書き込んだり(hogehogeの方)しています。
Unity用のコードを作成(CallTest.js)
今度は、Unityアプリの最前面にGUIを用意して、情報を取得したり、設定したりするボタンやラベルなどを用意してみます。このスクリプトファイルは、まあどこでもいいので「Assets」直下に、しかもJavascriptで用意してみます(このファイルは、C#でもJSでもどちらもでいいので)。
廣さんの本をがっつり参考にさせていただきました!
「CallTest.js」と名付けて、ダブルクリックして開きます。
OnGUI()でラベルやテキストフィールド、ボタンを用意して、ボタンが押されたら「readKeyChain()」や「setKeyChain()」が呼ばれるようにしてあります。それらの関数にある「NativePlugin.hoge()」でKeyChainからの情報を取得し、「NativePlugin.hogehoge(_text)」で_textの文字列をKeyChainに保存するような感じになっています。LabelStyleやTextFieldStyleで文字の大きさをUnityのインスペクタで設定できるようになっています。
作成した「CallTest.js」を中央に配置したキューブにでもアサインしておきます。キューブを選択してインスペクタ上の「Add Conponent」を押し、
「Script >」を押し、
次に表示される画面でJSの「Call Test」を選びます。
キューブにスクリプトがアサインされ、再度インスペクタで確認するとスクリプト内のLabelStyleとTextFieldStyleの値を細かく変更できるようになります。
ここで文字の大きさを調整します。(プレビューしながら文字調整もできますが、プレビューを終了すると元に戻るようなので注意)
ビルドしてXcode用プロジェクトを書き出す
いよいよビルドしてみます。まずは「Build Settings」を開きます。
「iOS」を選択し、「Run in Xcode as」を「Debug」に、「Add Current」を押して現在のシーンを追加します。そして、「Player Setting」を押すと、iOS書き出しに関する詳細な設定が、インスペクタ上に表示されます。
細かい設定がいろいろありますが、とりあえずここだけはという注意点は「Target minimum iOS Version」が「6.0」になっているのを「8.0」にします。(6.0のままだとXcode7.1でエラーが起こりますので)
また、Target SDKは「Device SDK」にします。これは実機で動作させるためのプロジェクトを書き出す設定で、Unityから書き出すXcodeプロジェクトは、この時点で実機用かシミュレータ用かを分けなければならないようです。Unity 5.2.3f1+Xcode 7.1.1(7B1005)時点では、ここで「Simulator SDK」を選択して書き出したプロジェクトでは、エラーが発生してシミュレータで動作できないようです。。
そして、「Build」ボタンを押して、出力先を選択します。
Unityは、ここで指定した保存先に、Xcodeのプロジェクト一式を書き出してくれます。書き出す際に設定する名前は、そこで使用されるフォルダ名になるだけだと思われます。
ここでもし既存のフォルダがあった場合は、Replace(置き換え)かAppend(追加)かを選ぶことになると思いますが、とりあえずここでは「Replace」を選んで、すべてその書き出しで作り直すようにした方がいいと思います。(Appendだと今のUnityの設定に問題があるのか、前に書き出したものに問題があるのかの判別がわかりにくくなったりしますので、いろいろ実験してる間はReplaceがいいと思います)
また、Unityが認識するスクリプト上にエラーがあったりすると、この書き出しの時点で書き出せません。エラーなく書き出せたとしても、次に出力後のXcode上でエラーが発生することはありますので、ある程度覚悟しておいた方がいいですね。
無事書き出せたら、こんな感じになります。「Unity-iPhone.xcodeproj」をダブルクリックするとXcodeが開きます。
Xcodeでビルド
書き出したXcodeプロジェクトは、実機用なのでiPhoneをMacにつないで実機でプレビューしてみます。
さぁ、ここでどれだけエラーが出て、それらが対処できるかどうか、ですね。。Xcodeもバージョンアップし、それにUnity側がどれだけ対応していけているか、もあるし、自分のミスもあります。そもそも間違っていることをやっているかもしれない。ここでの対処は、本当に苦労します。
この際、黄色い警告は完全無視し、とにかく赤く出てる「エラー」を回避して、Build Successに持ち込みたい。
ビルドすると3つエラーが出ました。。。。(これら3つを対処した後に、ビルドするとその先にまたエラーが発生、なんてこともありますね。。)
これらの3つのエラーは、いずれもSSKeyChainをUnity経由で組み込んだことによって参照できないようになっているからのようです。
これのトラブル解決は、出力後のXcodeで対処していくことになると思います、エラーがなくなるまで(この段階ではUnityに戻って対処する、なんて面倒なことはせず、Xcodeで原因追求に努めます)。で、その際の注意としては、それらのトラブルを回避した修正点は、最終的にUnityに組み込まれているファイルの方にも反映しておかないと、再度書き出したときに元に戻るということです。Unityからの書き出しの際にReplaceを行うと、修正したものもすべて上書きでなくなるので注意です。
Xcodeでどのような修正をすればいいか検証を終えたら、Unity内に含まれているファイルの修正をします。今回の問題では、まず、「Security」frameworkも必要でした(SSKeyChainのReadMeに書いてる)。Unityで「SSKeyChain.h」を選択している状態で(他のファイルでもいいようですが)インスペクタを開くと、必要なframeworkを含めることができます。「iOS」を選択して、その下の一覧から「Security」にチェックを入れておきます。
そして、「SSKeyChain.h」自体の修正もしますので、ダブルクリックして修正します。
「SSKeyChain.h」はこの部分だけ修正、
次に「SSKeychainQuery.h」を修正します。
さて、これでXcodeでも問題なくビルドできれば、実機で動作確認できます。「Build Setting」画面を開いてReplaceしてビルドしなおしてもいいし、この場合は、ファイルメニューの「Build & Run」で、Unitiからの書き出し→Xcodeでのビルド→実機での確認、の一連の流れを一気に行うこともできるかと思います。
他のアプリとの情報共有
ここまでのファイルがエラーなく書き出しできたなら、Unityからネイティブコードを呼び出して、SSKeyChainによってキーチェインに情報を保管し、それを呼び出す、ということができるようになったと思います。
※ Capabilitiesの「Keychain Sharing」はオフの状態でも自分のアプリのみで読み書きする上では使えるようです(もうちょい検証してみますが)
起動直後は、こんな画面。「data」部分はエディタブルテキストフィールドになっています。
Xcodeのコンソールにもキーチェイン情報の読み取り用のメソッドが呼ばれたことがログされました。
エディタブル部分をタップするとキーボードが現れて入力できます。
上の「set KeyChain」ボタンを押すと、入力した文字をキーチェインに保存できます。下の「read KeyChain」を押すとキーチェインの情報を中央のラベルの表示します。アプリを終了し起動しなおしてからでも情報を取得することができます。
こちらもXcodeでログが出てきました。
それでは最後に、他のアプリとの情報共有ができるかを試してみます。他のアプリと情報共有するには、Capabilitiesの「Keychain Sharing」と「App Groups」をオンにして仲間であることを設定しておかなければならないのだと思います。(本当に両方ともオンにする必要があるかは検証中です)
Keychain Sharingをオンにすると、Appleのメンバーセンターにつながり、アカウントを選択するダイアログが出ます。
もし、このときStepsのチェックにこのようなエラーが発生した場合は、
UnityのBuild SettingsからPlayer Settingsをインスペクタで開き、Bundle Identifierをデフォルトの「com.Company.ProductName」を
このようにユニークなものにしてあげてからビルドし直して試してみてください。
その状態で書き出したXcodeプロジェクトでKeychain Sharingをオンにすると、デフォルトでBundle Identifierの文字列が入ります。
ここに共有したいアプリ同士で同じ文字列を入れておけばアクセスできるようになります。ここでは、「com.mushikago.KeyChainTest1」と書き換えておきます。(追加でもいいはずです)「com.mushikago.KeyChainTest1」にしたのは、「NativePlugin.mm」のSSKeyChainでaccountパラメータを決め打ちで「com.mushikago.KeyChainTest1」と書いてテストしているからです。スクリプトとこの部分が一致していれば、任意の文字列に変更してかまいません。
次にAppleのメンバーセンターに行き、App Groupを用意します。
ここで用意したApp Groupが選択できるようになるので、これも共有したアプリ同士で同じものを選択しておきます。「group.com.mushikago.KeyChainTest」をこの一連のテストように使おうと思いおます。これも共有するアプリ間で同じものになっていれば、任意の文字列で用意してあげればOKです。
このCapabilitiesの「Keychain Sharing」と「App Groups」を同じように設定したアプリを別途用意します。Xcodeで標準のシンプルなアプリを作り、CocoaPodsでSSKeyChainをインストールし、起動直後にキーチェイン情報を取得、ボタンを押すとテキストを保存するというものを作りました。
GitHub : mushikago/KeyChainTest1
この標準アプリとUnityアプリの間でキーチェイン経由でデータのやり取りができれば成功です。
最終動作確認
Unityアプリを実機で動かし、「なにぬ」と入れてデータ保存。
次に、標準アプリを起動すると、Unityでデータ保存したキーチェイン情報が読み取られ「なにぬ」が表示されます。それをさらに「なにぬねの」と編集して「Set」ボタンを押し、同じ場所のキーチェインに保存。
再度、Unityアプリの戻り、「read KeyChain」を押すと標準アプリで更新したキーチェイン情報が読み取られ、「なにぬねの」が表示されます。
これで、アプリ間でキーチェイン情報を共有できたことがわかると思います。
問題としては、Unityから書き出した後のXcodeプロジェクトを修正してCapabilitiesを手動で設定している点です。これは再度、Unityからビルドを上書きするとまた元に戻ってしまいます。毎回このCapabilitiesを設定しなければなりません。この部分を自動化できないものか、現在確認しています。
※ Build Settingsの項目などであれば、こちら↓のような方法で自動化できました。
この辺りのことはまた研究してMEMOしていきたいと思います。
このMEMOでテストした Unityのプロジェクトと標準アプリのソースをGitHubに載せておきました。
東京造形大学卒業後、マクロメディア(現アドビ)に入社。QAやテクニカルサポートマネージャーとしてFlash、DreamweaverなどのWeb製品を担当。独立後、2007年に虫カゴデザインスタジオ株式会社を設立。2021年東京三鷹を拠点に。最近は、Unity, Unity Netcode for GameObjects, CakePHP, Laravel, ZBrush, Modo, Adobe Substance 3D, Adobe Firefly, Xcode, Apple Vision Pro, Firebaseにフォーカスしています。モバイルアプリ開発情報を主としたブログ「MUSHIKAGO APPS MEMO」の中の人。