Unity插件的NoClassDefFoundError和ClassNotFoundException

时间:2017-10-15 18:01:55

标签: java android unity3d

我正在为Android Studio中的Unity应用程序开发Android插件。该插件旨在访问Google Fit API,并提供可在Unity应用程序中显示的信息。我在下面包含了我的Java文件,并在本文末尾包含了我的Gradle文件和清单文件。

UnityPlayerActivity.java文件

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);
        }
    }
}

正确调用logInUnity()方法。我在我的C#脚本中使用Debug.Log()方法内的LogInUnity()方法记录事物。使用命令adb logcat -s Unity delvikvm DEBUG时,我可以在命令提示符中看到所有内容。

问题是访问Android支持库。当我在ActivityCompat.checkSelfPermission()方法中调用checkPermissions时,我的活动会立即强制完成。我已经在下面列出了有关崩溃的信息。

崩溃信息

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

我已将compile 'com.android.support:support-v4:25.3.1'包含在gradle文件的依赖项中。基于我已经完成的研究,我认为问题是Android支持库没有包含在我的jar文件中。不过,我可能错了。

尽管如此,我还没有尝试过。我发现许多类似的问题与Stack Overflow上的相同错误,我试图使用这些问题的答案中建议的许多事情来解决我的问题。但是,到目前为止,他们都没有工作过。

只是为了澄清,在添加ActivityCompat.checkSelfPermission()方法调用之前,一切正常。因此,问题必须在支持库中。

build.gradle文件

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文件

<?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>

2 个答案:

答案 0 :(得分:1)

我设法使用Play Services Resolver for Unity解决了我的问题。我按照README.md文件中详述的步骤操作,并包含*Dependencies.xml文件,其中包含以下内容:

<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>

解析器完成工作后,我的Project文件最终看起来像这样:

enter image description here

事后看来,我想知道从Android SDK文件夹下找到的文件导入这些文件是否足够。我想我之前已尝试过包含support-v4-25.3.1,但由于某种原因,我记得我没有工作。

在此之后以及明确授予应用程序ACCESS_FINE_LOCATION权限之后,我设法在命令提示符中获得以下输出,证明现在一切正常:

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   : 

答案 1 :(得分:0)

你遇到这个问题是因为你没有完全理解 gradle。

既然你正在开发一个android插件,我猜你是在开发aar或其他类型的库。在构建库时,gradle 不会将其他库中的代码包含到您的输出 aar 中,而只会包含类定义,因此如果您只是将输出 aar 放入您的统一项目中,那么当您的库尝试执行时,实际上预计会出现 NoClassDefFoundError从其他库调用代码。相反,当您尝试构建 apk 时,gradle 会将所有必要的代码编译到您的 apk 中,这样您就可以调用其他库中的代码。

因此,真正的解决方案是在从 Unity 项目构建应用程序时自定义您自己的 build.gradle。请参阅 https://docs.unity3d.com/Manual/android-gradle-overview.html 了解如何操作。在这里,您只需要自定义主 Gradle 模板。更新设置后,您应该可以在 Asset/Plugins/Android 中找到 mainTemplate.gradle。这是您的统一项目将用于构建您的 android apk 的模板。

这是我的模板:

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**

如您所见,您必须将 implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.6.21' 添加到依赖项中,以便您可以在构建时将此外部库中的代码编译到您的 apk 中。

顺便说一下,在构建您的 apk 时,这里的 **MINSDKVERSION** 等键将被您的选项替换为 unity。