質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.03%

Unityからaarファイル上にあるGooglePlayservicesが呼べない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,391

score 102

前提・実現したいこと

Unityでゲームを作っています。
セキュリティのためにこちらを参考にさせて頂き、GoogleのSafetyNetを利用したいのですが上手くいきません。
Android Studio側で、Android LibraryとしてGoogle Play servicesの処理をするクラスとそのサポートクラスからなるaarファイルを作り、Unity側(C#)から それを呼び出しています

なお、実機でテストしています

発生している問題・エラーメッセージ

コードをいじって試した結果、

  1. GoogleApiAvailabilityや、GoogleApiClient.Builder(getActivity())を呼び出す箇所に入ると「問題が発生したためアプリを終了します」のダイアログが表示され強制終了します。
  2. 、GooglePlayservicesへの接続・切断イベントを受け取るコールバックを加えた場合,Android Libraryを呼び出したときに以下のエラーがLogCatで出ます
エラーメッセージ
04-25 19:30:39.401 16799-16799/? I/Unity:AndroidJavaException: java.lang.NoClassDefFoundError: com.unity.unitygame.test_plugin.TestClass$2
                                          java.lang.NoClassDefFoundError: com.unity.unigame.test_plugin.TestClass$2
                                              at com.unity.unigame.test_plugin.TestClass.<init>(TestClass.java:144)
                                              at com.unity.unigame.test_plugin.ReqClass.<init>(ReqClass.java:41)
                                              at com.unity3d.player.ReflectionHelper.nativeProxyInvoke(Native Method)


このエラー内の
(TestClass.java:144)は private GoogleApiClient.ConnectionCallbacks mGoogleApiCallback=new GoogleApiClient.ConnectionCallbacks()

(ReqClass.java:41)はft.add(new TestClass(), "aiueoao");
を示してます。

いずれもUnity側からの呼び出しは問題なく出来ていると思います。
またAndroid LibraryとしてUnityから呼び出すのではなく、Android StudioだけでSafetyNetの呼び出しをするアプリを作成した場合は正常に呼び出すことができました。

エラーメッセージのNoClassDefFoundErrorについて調べたら、「クラスの定義が見つかりません」とあるのですが、まだ理由についてはわからない状態です。

該当のソースコード

//Android Studio側  Unityから使用されるヘルパークラス
package com.unity.unitygame.test_plugin;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;

public class ReqClass {

    //Unity側のこのインタフェースから派生クラスが作成されます
    public static interface IListener {
        public void onComplete(boolean status);
    }

    private Activity mActivity;
    private IListener mListener;

    public static ReqClass mListner = null;

    public static ReqClass instance() {
        return mListner;
    }

    public ReqClass(Activity a, IListener l) {
        mListner = this;

        mActivity = a;
        mListener = l;

        //フラグメントを作成し、アクティビティに追加します。
        FragmentManager fm = mActivity.getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        //FragmentTransaction.add() 
        ft.add(new TestClass(), "aiueoao");
        ft.commit();
    }

    // このメソッドが呼び出されるとリスナーに通知する
    public void onComplete(boolean v) {
        mListener.onComplete(v);
    }
}
//Android Studio側  SafetyNetの処理クラス
package com.unity.unitygame.test_plugin;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.util.Base64;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.safetynet.SafetyNet;
import com.google.android.gms.safetynet.SafetyNetApi;

import org.json.JSONException;
import org.json.JSONObject;

import static com.unity3d.player.UnityPlayer.UnitySendMessage;

public class TestClass extends Fragment{

    public TestClass(){}
    private GoogleApiClient mGoogleApiClient;  //GoogleAPIを使用するためのクライアント

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d("SafetyNet_Log","onCreateView");
        checkServiceAvailability();
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    //Google play servicesが利用可能かを確認する
    private void checkServiceAvailability() {
        Log.d("SafetyNet_Log", "checkServiceAvailability");
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            Log.d("SafetyNet_Log", "接続済み");
            SafetyStart();
        }
        Log.d("SafetyNet_Log", "未接続");


        //Google play servicesの利用可否をチェックする
        GoogleApiAvailability checker = GoogleApiAvailability.getInstance();  //getInstance() : GoogleApiAvailabilityのシングルトンインスタンスを返します。
        int result = checker.isGooglePlayServicesAvailable(getActivity());

        if (result == ConnectionResult.SUCCESS) {
            //使用可能
            Log.d("SafetyNet_Log", "ConnectionResult.SUCCESS");
            onGooglePlayServicesAvailable();
        } else {
            //使用不可
            Log.d("SafetyNet_Log", "使用不可");
        }
    }

    //Google Play開発者サービスが利用可能だった場合
    private void onGooglePlayServicesAvailable() {
        try {
            mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                    .addApi(SafetyNet.API)
          //          .addConnectionCallbacks(mGoogleApiCallback)               //コールバック
          //          .addOnConnectionFailedListener(mConnectionFaildListener)
                    .build();

            mGoogleApiClient.connect();
            Log.d("SafetyNet_Log", "build()");
            SafetyStart();
        }catch (Exception e){
            backUnity(e.toString());
        }
    }

    private void SafetyStart() {
        Log.d("SafetyNet_Log", "------SafetyStart()--------");
        //    mGoogleApiClient.connect();     //クライアントをGoogle Playサービスに接続します。
        byte[] nonce = {1, 2, 3, 4, 5, 6, 7,8,9,10,11,12,13,14,15,16,17,18}; // Should be at least 16 bytes in length.

        SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)
                .setResultCallback(new ResultCallback<SafetyNetApi.AttestationResult>() {

                    @Override
                    public void onResult(SafetyNetApi.AttestationResult result) {
                        String str = "";

                        Status status = result.getStatus();
                        if (status.isSuccess()) {
                            Log.d("SafetyNet_Log", "ok");
                            //サービスとの通信が成功したことを示します。  result.getJws Result()を使用して結果データを取得します。
                            String[] jwtParts = result.getJwsResult().split("\\.");
                            String decodedPayload = new String(Base64.decode(jwtParts[1], Base64.DEFAULT));
                            try {

                                JSONObject root = new JSONObject(decodedPayload);
                                Log.d("SafetyNet JWT: ", root.toString());
                                str = root.toString();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.d("SafetyNet_Log", "No");
                            //サービスとの通信中にエラーが発生
                        }
                        backUnity(str);
                    }
                });
    }

    /*

    //GooglePlayServicesへの接続・切断イベントを受け取るコールバック
    private GoogleApiClient.ConnectionCallbacks mGoogleApiCallback=new GoogleApiClient.ConnectionCallbacks(){
        @Override
        public void onConnected(Bundle bundle) {
            //接続に成功した場合呼ばれる
            Log.d("SafetyNet_Log","onConnected!!!!");
            SafetyStart();
        }

        @Override
        public void onConnectionSuspended(int i) {
            Log.d("SafetyNet_Log","onConnectionSuspended!!!!");
        }
    };

    //GooglePlayServicesへの接続失敗イベントを受け取るコールバック
    private GoogleApiClient.OnConnectionFailedListener mConnectionFaildListener =new GoogleApiClient.OnConnectionFailedListener()
    {
        @Override
        public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
            Log.d("SafetyNet_Log","onConnectionFailed");
            if(connectionResult.hasResolution()){
                //何らかの方法で解決可能な場合
                Log.d("SafetyNet_Log","connectionResult.hasResolution()==true");
            }else {
                Log.d("SafetyNet_Log","connectionResult.hasResolution()==false");
            }
        }
    };
*/

    private void backUnity(String str)
    {
        Log.d("tes","----------------back unity");
        UnitySendMessage("CallbackGameObject", "SafetyTest_Callback", str);
    }
}

補足情報(言語/FW/ツール等のバージョンなど)

Android Studio2.1.2
Unity5.5.0(C#)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

GooglePlayServicesの中から、必要なAPIのみを追加するためのUnityライブラリを使うことで解決しました
参考

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る