How to make Unity Native Plugin (Android version)

Overview

If you want to make the SDK developed for Android compatible with Unity apps, you need to create a plug-in to bridge the SDK and Unity apps. There are multiple ways to implement native plugins for Android, but this article will introduce a method that inherits UnityPlayerActivity. Please refer to Common for the implementation of common parts with the iOS plug-in.

Plugin side

BaseNativeActivity BaseNativeActivity is a class that inherits UnityPlayerActivity. It plays the role of Wrapper by calling the method of the class defined in SDK such as Sample and SampleLifecycle on behalf of it.

BaseNativeActivity


public class BaseNativeActivity extends UnityPlayerActivity {
    public static final void setCallbackGameObjectName(String name) {
        SampleUnityListener.getInstance().setCallbackGameObjectName(name);
    }

    @Override
    protected void onStart() {
        super.onStart();
        SampleLifecycle.onStart(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        SampleLifecycle.onResume(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        SampleLifecycle.onPause(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        SampleLifecycle.onDestroy();
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        return super.onPrepareOptionsMenu(menu);
    }

    public void start(String sampleCode) {
        Sample.getInstance().start(this);
    }

    public void doSomething() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Sample.getInstance().doSomething()
            }
        });
    }

    public int getScore() {
        return Sample.getInstance().getScore();
    }

    public String getSomeText() {
        return Sample.getInstance().getSomeText();
    }

    public boolean isAvailable() {
        return Sample.getInstance().isAvailable();
    }
}

SampleUnityListener SampleUnityListener is a class to convey the callback on the SDK side to Unity side. It implements SampleListener, a listener class defined on the SDK side.

SampleUnityListener


public class SampleUnityListener implements SampleListener {
    private static final Sample sample = Sample.getInstance();
    private static SampleUnityListener instance;
    private String callbackGameObjectName;

    public synchronized static SampleUnityListener getInstance() {
        if (instance == null) {
            instance = new SampleUnityListener();
            sample.setListener(instance);
        }

        return instance;
    }

    public final void setCallbackGameObjectName(String name) {
        callbackGameObjectName = name;
    }

    @Override
    public void onStatusChanged(SampleStatus status) {
        if (callbackGameObjectName != null) {
            String statusIndex = String.valueOf(status.ordinal());
            UnityPlayer.UnitySendMessage(callbackGameObjectName, "_Sample_didStatusChange", statusIndex);
        }
    }
}

build.grade This is an example of build.gradle. In addition to the SDK itself (SampleSDK-*. Jar), classes.jar is included in the libs directory to import classes such as UnityPlayerActivity, but it is excluded because it is unnecessary at build time. Also, since it is necessary to resolve the name from the Unity side, minify is also set to false.

build.gradle


apply plugin: 'com.android.library'

android {
    compileSdkVersion 26
    buildToolsVersion "25.0.3"
    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:26.+'
}

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

About build

For Android Studio, you can create aar from Build-> Make Module. It's a good idea to put the built aar under Assets / Plugins / Android of the Unity project. Also, please refer to here for how to get the classes.jar used at compile time.

Unity side

Sample_Android.cs Sample_Android.cs is a class that implements ISample, and by accessing the class (BaseNativeActivity) implemented on the plugin side, the Unity app and SDK We will bridge.

Sample_Android.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

public class Sample_Android : ISample {
    private Sample sampleGameObject;
    private SampleEventListener listener;
    private static AndroidJavaObject androidInstance;

    public Sample_Android(Sample sampleParent) {
        sampleGameObject = sampleParent;

        InitAndroidInstance();
        CreateListenerObject();

        if (sampleParent.androidSampleCode != null) {
            Start(null);
        }
    }

    private void CreateListenerObject() {
        listener = sampleGameObject.gameObject.AddComponent<SampleEventListener>();

        using (AndroidJavaObject activityObject = GetCurrentActivity()) {
            activityObject.CallStatic("setCallbackGameObjectName", sampleGameObject.gameObject.name);
        }

        listener.SetNativeParent(this);
    }

    public void Start(string sampleCode) {
        using (AndroidJavaObject activityObject = GetCurrentActivity()) {
            if (sampleGameObject.androidSampleCode != null) {
                activityObject.Call("start", sampleGameObject.androidSampleCode);
            } else if (sampleCode != null) {
                activityObject.Call("start", sampleCode);
            }
        }
    }

    public void DoSomething() {
        using (AndroidJavaObject activityObject = GetCurrentActivity()) {
            activityObject.Call("doSomething");
        }
    }

    public int GetScore() {
        using (AndroidJavaObject activityObject = GetCurrentActivity()) {
            return activityObject.Call<int>("getScore");
        }
    }

    public SampleStatus GetStatus() {
        SampleStatus status = SampleStatus.Unavailable;

        using (AndroidJavaObject statusObject = androidInstance.Call<AndroidJavaObject>("getStatus")) {
            string statusName = statusObject.Call<string>("name");

            if (statusName.Equals("Unavailable")) {
                status = SampleStatus.Unavailable;
            } else if(statusName.Equals("Available")) {
                status = SampleStatus.Available;
            }
        }

        return status;
    }

    public string GetSomeText() {
        return androidInstance.Call<string>("getSomeText");
    }

    public bool IsAvailable() {
        using (AndroidJavaObject activityObject = GetCurrentActivity()) {
            return activityObject.Call<bool>("isAvailable");
        }
    }

    public AndroidJavaObject GetCurrentActivity() {
        using (AndroidJavaClass playerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
            return playerClass.GetStatic<AndroidJavaObject>("currentActivity");
        }
    }

    protected static void InitAndroidInstance() {
        using (AndroidJavaClass sampleClass = new AndroidJavaClass("com.sdk.Sample")) {
            androidInstance = sampleClass.CallStatic<AndroidJavaObject>("getInstance"); 
        }
    }
}

AndroidManifest.xml This is an example of Android Manifest placed under Assets / Plugins / Android of Unity project. The above-mentioned Base Native Activity is described.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.unity3d.player"
	  android:installLocation="preferExternal"
	  android:theme="@android:style/Theme.NoTitleBar"
	  android:versionCode="1" android:versionName="1.0">
  <supports-screens android:smallScreens="true"
		    android:normalScreens="true"
		    android:largeScreens="true"
		    android:xlargeScreens="true"
		    android:anyDensity="true" />
  <application android:label="@string/app_name" android:debuggable="false">
    <activity android:name="com.sample.plugin.BaseNativeActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
    </activity>
  </application>
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

Proguard If you want to make settings such as avoiding Minification for some classes, create proguard-user.txt and place it under Assets / Plugins / Android of Unity project, and it will be automatically exported as an Android project. It will be reflected.

proguard-user.txt (example)


-keepattributes *Annotation*
-keepattributes Signature
-keep class com.sample.sdk.** {
  public <fields>;
  public <methods>;
}

-keep class com.sample.plugin.** {
    public <fields>;
    public <methods>;
}

-dontwarn com.sample.sdk.**

Directory structure

Place the following under Assets / Plugins / Android of the Unity project as needed. --SDK body (jar / aar) --Plugins (jar / aar)

reference

https://docs.unity3d.com/ja/540/Manual/PluginsForAndroid.html

Recommended Posts

How to make Unity Native Plugin (Android version)
How to write React Native bridge ~ Android version ~
How to make a Jenkins plugin
[Android] How to make Dialog Fragment
[Unity] I tried to make a native plug-in UniNWPathMonitor using NWPathMonitor
How to make shaded-jar
How to make an crazy Android music player
How to use Struts2 * Spring Framework (Spring plugin) June 2017 Version
How to lower java version
Java --How to make JTable
How to check JSF version
[Rails] How to make seed
[2020 version] How to send an email using Android Studio Javamail
How to make an app using Tensorflow with Android Studio
How to "hollow" View on Android
How to make a JDBC driver
How to make a splash screen
How to make a Maven project
How to make a Java array
Android: How to deal with "Could not determine java version from '10 .0.1'"
How to make a Java calendar Summary
[Android] How to deal with dark themes
How to detect microphone conflicts on Android
How to make a Discord bot (Java)
How to install the legacy version [Java]
How to make asynchronous pagenations using Kaminari
How to add application version information to Sentry information
How to make an app with a plugin mechanism [C # and Java]
How to use ExpandableListView in Android Studio
[Android] How to convert a character string to resourceId
How to make rbenv recognize OpenSSL on WSL
[Android] How to detect volume change (= volume button press)
How to make Spring Boot Docker Image smaller
Using Native UI Component with React Native (Android version)
Make software that mirrors Android screen to PC 1
How to make duplicate check logic more readable
How to make a lightweight JRE for distribution
How to use nfs protocol version 2 with ubuntu 18.04
How to make a follow function in Rails
How to run NullpoMino 7.5.0 on Ubuntu 20.04.1 64bit version
[Java] How to make multiple for loops single
How to make a Vagrant Plugin that you learned when you forked and published vagrant-mutagen
How to deploy
How to make an image partially transparent in Processing
How to make batch processing with Rails + Heroku configuration
How to make a factory with a model with polymorphic association
[Android Studio] How to change TextView to any font [Java]
How to make Java unit tests (JUnit & Mockito & PowerMock)
How to make an almost static page with rails
How to organize information to make programming learning more efficient
[Ruby] How to use rbenv (version `x.x.x'is not installed)
How to make JavaScript work on a specific page
[Android Studio] [Java] How to fix the screen vertically
How to use Truth (assertion library for Java / Android)
[Android] How to get the setting language of the terminal
App development beginners tried to make an Android calculator app
How to make Laravel faster with Docker for Mac
How to prevent editTextPreference of android PreferenceFragmentCompat from breaking
Install MySQL 5.6 on CentOS6 [How to specify the version]
How to pass image pixel information natively from Unity
How to download the old version of Apache Tomcat