その他
    ホーム イベント 【成果発表会】「”ゲーム+何か”が求められる時代に挑戦」Unityネイティブプラグインで困った話(Android編)
    【成果発表会】「”ゲーム+何か”が求められる時代に挑戦」Unityネイティブプラグインで困った話(Android編)
     

    【成果発表会】「”ゲーム+何か”が求められる時代に挑戦」Unityネイティブプラグインで困った話(Android編)

    今回は社内の成果発表会「P-Review ’19」にて発表した、エンジニア 徳元 湧さんの資料を紹介します。
    ※この記事は個人の研究発表であり、会社としての見解ではございません。

    徳元 湧
    2019年4月アピゲー部にエンジニアとして入社。
    入社後は主にゴエティアクロスでUnity業務。

    preview-19g

    (※挨拶省略)

    このスライドで何が得られるか?

    突然ですが、早起きしただけで10連ガチャ分のなにかをもらえるんだったら早起きしたくなりませんか?

    これからのゲームの在り方として「ゲーム+何か」を考えた時、自分が健康的に過ごすためにも「ゲーム+ヘルスケア」は流行ってくるのではないかと考えました。
    ということで早速、Unityで作り始めてみました!

    ですが、Unityで作成するゲームとヘルスケアなどの端末機能を連動させる場合、Unityでは完結できず、「IOSならIOS」「AndroidならAndroid」といった各OSごとに用意されたネイティブAPIを利用しないとできないということに、作り始めてから気が付きました。

    それを検索しても技術の資料が殆ど無くて大変困ったので、研究成果としてゲーム+ヘルスケアを実現する基礎技術の共有をします!

    ネイティブプラグインとは

    ネイティブプラグインとは、UnityからAndroidやiOS等、OS固有の機能を呼び出すためのプログラムです。

    この具体例の画像はAndroidなんですが、こういった通知機能はUnityだけでは完結できず、ネイティブの機能を使って通知を飛ばしているんです。
    TwitterやFacebook連携をするゲームがよくありますが、あれもUnityだけでは判別ができません。

    今回はとっかかりとして、ヘルスケアでよくある機能「歩数計」を作ってみたので、どういうところで詰まったかというポイントなどを発表していきます。

    ネイティブプラグインの実装手順

    1.欲しい機能を各OSごとに使われている言語で作る。
    ※AndroidならJavaで作ります。

    2.そのプログラムをUnity内のPluginフォルダに組み込む。
    ※Androidの場合はaarなどにビルドする必要があります。

    3.UnityのC#スクリプトからプラグインの関数を呼び出す

    ざっくりですが、このような感じで機能を使うことになります。

    歩数計アプリを作る

    そして、自分がイメージした歩数計に必要な機能です。

    1.日毎の歩数を取得
    昨日は8千歩、今日は1万歩といった感じで、日毎に歩数を見れるものが欲しい。

    2.リアルタイムに歩いた歩数を更新
    アプリを起動しているときに歩いていたらすぐ更新されるものが欲しい。

    3.アプリを起動してない時も歩数を記録
    スマホをずっと持っていなくても記録されるものが欲しい。

    4.一定歩数に達した場合に通知を飛ばす
    例えば1万歩歩いたとして、その達成感を出すために通知を飛ばす機能が欲しい。

    この4つを達成する歩数計が欲しい!!
    でも作る前に、要件を満たす歩数計はないか一応探してみたところ「Asset Store」に歩数計プラグインが500円であったので買ってましたが…。

    • 日付を跨いだ時にバグが起きてしまう。
    • 欲しかった通知機能がない。
    • 通知バーに表示されるアイコンが変更できない。

    これ以外にもいくつかあったのですが、どれも今回の要件を満たすことができませんでした。

    やはり自作するしかない。

    検索してみた

    まずネイティブプラグインを作ってみようとなった時、その手順が載っているか調べてみたところ、いっぱい出てきました!

    しかも、プロジェクトを作る最初の段階から、それを組み込むまでのすべてを書いているものもありました。
    これさえあれば、すぐにネイティブプラグインを作ることができる状態にまでなりました。

    参考サイト:Androidネイティブ開発のすすめ

    そして次は、Android公式のディファレンスがありました。

    参考サイト: モーションセンサー(AndroidDevloper公式)

    ここはサンプル講座付きでしっかり書いてあるので、ここを見れば歩数計の情報がわかります!

    Javaで歩数を取得する
    SensorManagerクラスを使う

    先ほどのサイトでSensorManagerクラスを使えば、歩いた時こいつが処理をしてくれると。
    その処理を検知して、こちら側で処理をしてやれば反映できるのではないかという情報が分かりました。

    • SensorManagerに使うセンサーと、そのセンサーが働いた際に処理させるメソッドを登録する。
    • 今回は歩数をキャッチしたいので”TYPE_STEP_COUNTER”
    • これでスマホが歩行を検知したら、登録したコールバックが呼ばれる 。

    情報もそろっているし、歩数計アプリが作れるのでは…?

    だめでした。

    発覚した問題点

    • 謎の存在”Context”と”Activity”

    • 歩数の情報が単純な呼び出しでは取得できなかった

    • アプリ起動してない時にも歩数記録する方法がわからない

    UnityとAndroidネイティブ処理を繋ぐ部分の資料が殆どありませんでした… 。
    ネイティブプラグインを作る歩数計の処理はあったんですが、それをそのままコピペしても全然動いてくれませんでした。

    ここからは問題点と、その解決法を説明していきます。

    ContextとActivity

    Androidの開発をしていると、 Contextを引数に取る場面が非常に多いんです。

    このContextを取得するには、Activityの情報も必要だったのでどちらもしっかり調べました!

    Context
    Androidの色々な機能を使用するためのインターフェイス
    主にアプリ間の情報の受け渡しなどで使用するもの

    Activity
    Androidアプリにおけるメイン画面と紐づいたクラス
    Unityアプリの場合は、Unityが自動で生成してくれる

    ContextとActivity 解決編

    Contextを取得するにはActivityが必要なんですけど、Unityが勝手に作ってしまってくれているので、プラグイン側でActivityを持っていなかったのが問題になっていました。

    ですが、Unityさんはちゃんとそこを考えていてActivityを取得出来るメソッドが用意されていました。
    Androidのプロジェクト内にUnityのAPIを追加すれば、Activityを取ることができました。

    C#(Unity)

    Unity側であらかじめContextを取得して、引数としてネイティブ側に渡すことも出来ました。

    これで解決です。

    歩数の取得の問題

    最初の方に、Unityからネイティブプラグインを呼び出せばその機能が使えると言いましたが、歩数を取得するには呼び出すだけじゃ足りず、検知を続けるためにセンサーをずっと稼働させておくという処理が必要だったんです。

    そこで、解決方法として「Service」を使用します。

    Serviceを使用で解決

    Serviceとは、画面を持たないアプリケーションのようなものです。

    皆さんもスマホでアラームとか設定したことあるかと思うんですが、ずっと画面を起動していなくても時間になったら呼び出してくれるじゃないですか?
    アプリが後ろにいてもデータをダウンロードし続けてくれてるゲームとかもあると思うんですが、あれはServiceというのを使って動かしています。

    そしてそれには2種類の立ち上げ方が存在します。

    startService()
    ● Unityとは別プロセスで動かし続けれるため、アプリを落としても継続して動作する。
    データの取得などを直接出来ない。

    bindService()
    ● Unityのプロセスと同期させることでデータの取得などが可能になるが、Unityのアプリを落とすとこちらも落ちてしまう。

    今回はアプリを起動していないときでも歩数を計測したいので、startService()を使用します!
    ですが、Android 8(Oreo)から電池消費などの管理が厳しくなったことにより、ユーザーに通知せず裏でサービスを動かすことが出来なくなってしまいました。

    そのため、サービスを立ち上げるのにUnityのAndoridManifest内に、Serviceを許可の処理を書く必要があります。

    赤枠内

    android:processは書かなくても動くんですが、その場合アプリを落とした際にサービスも一度落ちてから、再びサービスだけ再起動するという不安定なことになるのであまりオススメはできません。

    Unityアプリとのデータ連携(研究中)

    Bindサービスはアプリと連携して消えてしまう話をしたんですが、Bindサービスの利点はUnity側の呼び出したオート連携が簡単にできるんです。
    ですが、そうではないstartForegroundService()ではデータの連携が直接はできないんです。

    これをどうやって解決したかというと、歩数のデータをテキストデータとしてAndroid内に書き出してそれを読み込むという少しめんどくさい処理で解決しました。
    この処理はなんだかなぁという感じで今も研究中です。

    (※歩数センサーが働くたびに書き込むと重いので50歩に一度情報を更新するなどの工夫が必要でした。)

    まとめ

    自分がネイティブAPIを利用した開発手順です!よかったら参考にしてください。

    1.まずはAssetStoreやGithubで欲しいプラグインを探す。

    2.無い場合はネイティブアプリで実装されている例を見つける。

    3.ContextやActivityの部分をUnityの実装に置き換える。

    4.独立したプロセスが必要な処理はServiceを使う。

    今回「ゲーム+ヘルスケア」を目標としてやってきましたが、これ以外にも色んなゲームを作っていきたいと思います。

    皆さんもOSの面白い機能や最新の機能を自由に使いこなして、「ゲーム+何か」が求められる時代に挑戦していきましょう!

    ひらめきの芽を咲かせ続ける徳元氏

    参考資料が少ない中、理想通りに作るのは大変だったみたいですね…。
    「ゲーム+アイコ」にもぜひ挑戦してください~!!

    記事を共有