Reputation: 93
I am developing an Android plugin for a Unity application in Android Studio. The plugin aims to access the Google Fit API, and provide information that can then be displayed in the Unity application. I have included my Java file below, and my Gradle file and Manifest files at the end of this post.
UnityPlayerActivity.java file
package com.kasperiekqvist.player;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import com.google.android.gms.common.api.GoogleApiClient;
import com.unity3d.player.UnityPlayer;
import java.text.SimpleDateFormat;
import java.util.Date;
public class UnityPlayerActivity extends com.unity3d.player.UnityPlayerActivity {
private GoogleApiClient mClient = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
logInUnity("onCreate", null);
super.onCreate(savedInstanceState);
checkPermissions();
}
/* SNIP */
private boolean checkPermissions() {
int permissionState = ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION);
boolean hasPermission = permissionState == PackageManager.PERMISSION_GRANTED;
logInUnity("checkPermissions", new String[] { "ACCESS_FINE_LOCATION:" + hasPermission });
return hasPermission;
}
private void logInUnity(String methodName, String[] linesToLog) {
if(methodName != null) {
String message = "UnityPlayerActivity:" + methodName + " was called at ";
message += new SimpleDateFormat("MM-dd HH:mm:ss").format(new Date());
if(linesToLog != null) {
for(int i = 0; i < linesToLog.length; i++) {
message += ";" + linesToLog[i];
}
}
UnityPlayer.UnitySendMessage("JavaCallback", "LogInUnity", message);
}
}
}
The logInUnity()
method gets called properly. I am logging things using the Debug.Log()
method inside my LogInUnity()
method in my C# script. I can see everything in the Command Prompt when using the command adb logcat -s Unity delvikvm DEBUG
.
The problem is accessing the Android Support Library. When I call ActivityCompat.checkSelfPermission()
in my checkPermissions
method, my Activity is force finished immediately. I have included the information on the crash below.
Crash info
10-15 19:57:53.843 18197 18197 E AndroidRuntime: FATAL EXCEPTION: main
10-15 19:57:53.843 18197 18197 E AndroidRuntime: Process: com.kasperiekqvist.androidpluginproject, PID: 18197
10-15 19:57:53.843 18197 18197 E AndroidRuntime: java.lang.Error: FATAL EXCEPTION [main]
10-15 19:57:53.843 18197 18197 E AndroidRuntime: Unity version : 2017.2.0f3
10-15 19:57:53.843 18197 18197 E AndroidRuntime: Device model : OnePlus ONEPLUS A5000
10-15 19:57:53.843 18197 18197 E AndroidRuntime: Device fingerprint: OnePlus/OnePlus5/OnePlus5:7.1.1/NMF26X/09131759:user/release-keys
10-15 19:57:53.843 18197 18197 E AndroidRuntime:
10-15 19:57:53.843 18197 18197 E AndroidRuntime: Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/app/ActivityCompat;
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at com.kasperiekqvist.player.UnityPlayerActivity.checkPermissions(UnityPlayerActivity.java:74)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at com.kasperiekqvist.player.UnityPlayerActivity.onCreate(UnityPlayerActivity.java:27)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:6743)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1134)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2715)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2848)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.app.ActivityThread.-wrap12(ActivityThread.java)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1552)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6334)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.app.ActivityCompat" on path: DexPathList[[zip file "/data/app/com.kasperiekqvist.androidpluginproject-2/base.apk"],nativeLibraryDirectories=[/data/app/com.kasperiekqvist.androidpluginproject-2/lib/arm, /data/app/com.kasperiekqvist.androidpluginproject-2/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
10-15 19:57:53.843 18197 18197 E AndroidRuntime: ... 14 more
10-15 19:57:53.843 18197 18197 D AppTracker: App Event: crash
10-15 19:57:53.846 1804 16770 W ActivityManager: Force finishing activity com.kasperiekqvist.androidpluginproject/com.kasperiekqvist.player.UnityPlayerActivity
10-15 19:57:53.848 1804 16770 D ActivityTrigger: ActivityTrigger activityPauseTrigger
10-15 19:57:53.849 18197 18197 I Process : Sending signal. PID: 18197 SIG: 9
10-15 19:57:53.851 4741 6303 D OPReportService: addMonitorFolder onEvent path=data_app_crash@2017-10-15-19_57_53_851.txt, event:128
10-15 19:57:53.860 1804 4733 D EmbryoManager: prepare com.kasperiekqvist.androidpluginproject
10-15 19:57:53.860 1804 4733 I ActivityManager: Process com.kasperiekqvist.androidpluginproject (pid 18197) has died
10-15 19:57:53.860 1804 4733 D ActivityManager: get process top duration : com.kasperiekqvist.androidpluginproject, duration : 45
10-15 19:57:53.860 1804 4733 D ActivityManager: cleanUpApplicationRecord -- 18197
I have included compile 'com.android.support:support-v4:25.3.1'
in the dependencies of my gradle file. Based on the research I've done, I think the problem is that the Android Support Library is not included in my jar file as it should be. I could be wrong about that, though.
Nevertheless, I am running out of things to try. I found many similar problems with the same errors on Stack Overflow, and I tried to solve my issue using many of the things suggested in the answers of those questions. However, so far none of them have worked.
And just to clarify, everything worked properly before adding the ActivityCompat.checkSelfPermission()
method call. So, the problem must be with the Support Library.
build.gradle file
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "26.0.2"
defaultConfig {
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
compile 'com.google.android.gms:play-services-fitness:11.0.4'
compile 'com.android.support:support-v4:25.3.1'
}
AndroidManifest.xml file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.kasperiekqvist.androidpluginproject" xmlns:tools="http://schemas.android.com/tools" android:versionName="1.0" android:versionCode="1" android:installLocation="preferExternal">
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
<application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner">
<activity android:name="com.kasperiekqvist.player.UnityPlayerActivity" android:label="@string/app_name" android:screenOrientation="fullSensor" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
<meta-data android:name="unity.build-id" android:value="c9792a78-0123-4f4b-be86-1b85de56f689" />
<meta-data android:name="unity.splash-mode" android:value="0" />
<meta-data android:name="unity.splash-enable" android:value="True" />
<meta-data android:name="android.max_aspect" android:value="2.1" />
</application>
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="25" />
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.hardware.vulkan" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
</manifest>
Upvotes: 1
Views: 4594
Reputation: 31
You are getting this problem because you do not fully understand gradle.
Since you are developing an android plugin, I guess you are developing a aar or other kinds of library. When building a library, gradle will not include code from other library into your output aar, instead it will just include the class definition, so if you simply put your output aar into your unity project, then NoClassDefFoundError is actually expected when your library try to call codes from other library. Instead, when you try to build an apk, gradle will compile all necessary code into your apk, that's how you are able to call codes from other libraries.
So, the true solution is to custom your own build.gradle when building your app from unity project. See https://docs.unity3d.com/Manual/android-gradle-overview.html for how to do it. Here you just need Custom Main Gradle Template. After you update the settings, you should be able to find mainTemplate.gradle in Asset/Plugins/Android. This is the template that your unity project will use to build your android apk.
Here is my template:
apply plugin: 'com.android.library'
**APPLY_PLUGINS**
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.6.21'
**DEPS**}
android {
compileSdkVersion **APIVERSION**
buildToolsVersion '**BUILDTOOLS**'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion **MINSDKVERSION**
targetSdkVersion **TARGETSDKVERSION**
ndk {
abiFilters **ABIFILTERS**
}
versionCode **VERSIONCODE**
versionName '**VERSIONNAME**'
consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
}
lintOptions {
abortOnError false
}
repositories {
flatDir{
dirs 'libs'
}
google()
jcenter()
}
aaptOptions {
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
}**PACKAGING_OPTIONS**
}**REPOSITORIES****SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**
As you can see, you must add implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.6.21'
to dependencies so that you can compile codes from this external library into your apk when building.
By the way, here keys like **MINSDKVERSION**
will be replaced with your options by unity when building your apk.
Upvotes: 1
Reputation: 93
I managed to solve my problem by using the Play Services Resolver for Unity. I followed the steps detailed in the README.md
file, and included the *Dependencies.xml
file with the following content:
<dependencies>
<androidPackages>
<androidPackage spec="com.android.support:support-v4:25.3.1">
<androidSdkPackageIds>
<androidSdkPackageId>extras-android-m2repository</androidSdkPackageId>
</androidSdkPackageIds>
<repositories>
<repository>https://maven.google.com</repository>
</repositories>
</androidPackage>
</androidPackages>
</dependencies>
After the Resolver had done its work, my Project files ended up looking like this:
In hindsight, I wonder if it would have been enough to import these files from the files found under the Android SDK folder. I think I tried including the support-v4-25.3.1
previously already, but for some reason I remember that not working.
After this and after explicitly giving the ACCESS_FINE_LOCATION
permission to the app, I managed to get the following output in my Command Prompt which proved that everything now works:
10-15 23:43:26.574 3438 3693 I Unity : UnityPlayerActivity:checkPermissions was called at 10-15 23:43:23
10-15 23:43:26.574 3438 3693 I Unity : ACCESS_FINE_LOCATION:true
10-15 23:43:26.574 3438 3693 I Unity :
10-15 23:43:26.574 3438 3693 I Unity : (Filename: ./artifacts/generated/common/runtime/DebugBindings.gen.cpp Line: 51)
10-15 23:43:26.574 3438 3693 I Unity :
Upvotes: 1