IBM Mobile First 7.1 - 推动混合 Android 应用程序 - 未找到 Dex Class

IBM Mobile First 7.1 - Push on Hybrid Android App - Dex Class not Found

我最近为我们的一位客户实现了一个基于混合 cordova 的应用程序,并根据 MFP 文档向其添加了推送通知。

几乎一切正常,注册广播推送事件,通过 MFP 服务器发送和接收它们并在 Javascript 中处理它们。如果应用程序未激活,推送通知会显示在通知栏上,这没问题。

但是,点击它不会启动应用程序,因此我的 javascript 代码永远不会收到通知。

相反 Logcat 显示此异常:

03-10 15:47:37.489: E/Parcel(3190): Class not found when unmarshalling: com.worklight.wlclient.push.GCMIntentService$Message
03-10 15:47:37.489: E/Parcel(3190): java.lang.ClassNotFoundException: com.worklight.wlclient.push.GCMIntentService$Message
03-10 15:47:37.489: E/Parcel(3190):     at java.lang.Class.classForName(Native Method)
03-10 15:47:37.489: E/Parcel(3190):     at java.lang.Class.forName(Class.java:308)
03-10 15:47:37.489: E/Parcel(3190):     at java.lang.Class.forName(Class.java:272)
03-10 15:47:37.489: E/Parcel(3190):     at android.os.Parcel.readParcelableCreator(Parcel.java:2275)
03-10 15:47:37.489: E/Parcel(3190):     at android.os.Parcel.readParcelable(Parcel.java:2239)
03-10 15:47:37.489: E/Parcel(3190):     at android.os.Parcel.readValue(Parcel.java:2146)
03-10 15:47:37.489: E/Parcel(3190):     at android.os.Parcel.readArrayMapInternal(Parcel.java:2479)
03-10 15:47:37.489: E/Parcel(3190):     at android.os.BaseBundle.unparcel(BaseBundle.java:221)
03-10 15:47:37.489: E/Parcel(3190):     at android.os.BaseBundle.getString(BaseBundle.java:918)
03-10 15:47:37.489: E/Parcel(3190):     at android.content.Intent.getStringExtra(Intent.java:5440)
03-10 15:47:37.489: E/Parcel(3190):     at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1871)
03-10 15:47:37.489: E/Parcel(3190):     at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1409)
03-10 15:47:37.489: E/Parcel(3190):     at com.android.server.am.ActivityManagerService.startActivityInPackage(ActivityManagerService.java:5565)
03-10 15:47:37.489: E/Parcel(3190):     at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:257)
03-10 15:47:37.489: E/Parcel(3190):     at com.android.server.am.PendingIntentRecord.send(PendingIntentRecord.java:197)
03-10 15:47:37.489: E/Parcel(3190):     at android.content.IIntentSender$Stub.onTransact(IIntentSender.java:64)
03-10 15:47:37.489: E/Parcel(3190):     at android.os.Binder.execTransact(Binder.java:446)
03-10 15:47:37.489: E/Parcel(3190): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.worklight.wlclient.push.GCMIntentService$Message" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
03-10 15:47:37.489: E/Parcel(3190):     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
03-10 15:47:37.489: E/Parcel(3190):     at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
03-10 15:47:37.489: E/Parcel(3190):     at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
03-10 15:47:37.489: E/Parcel(3190):     ... 17 more
03-10 15:47:37.489: E/Parcel(3190):     Suppressed: java.lang.ClassNotFoundException: com.worklight.wlclient.push.GCMIntentService$Message
03-10 15:47:37.489: E/Parcel(3190):         at java.lang.Class.classForName(Native Method)
03-10 15:47:37.489: E/Parcel(3190):         at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
03-10 15:47:37.489: E/Parcel(3190):         at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
03-10 15:47:37.489: E/Parcel(3190):         at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
03-10 15:47:37.489: E/Parcel(3190):         ... 18 more
03-10 15:47:37.489: E/Parcel(3190):     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

我检查了 dexed classes 并且存在内部 classes。尽管如此,dex classloader 拒绝 find/load 它们。我还仔细检查了 activity 名称、权限以及我在 Stack Overflow 等网站上找到的所有其他内容,但无济于事。应用程序可以正常接收 Intent,但无法处理它,因为 dex class 加载程序中缺少内部 class。

这是没有 ProGuard 的调试版本。我还将项目从 Eclipse/ADT/ANT 迁移到 Android Studio/Gradle 只是为了面对同样的问题,所以我认为这与 GCM 库或构建过程本身无关。这可能与 dex 路径有关,但我不知道如何分析或修复它。

由于所涉及的库的大小(Google Play 和 Mobile First)我不得不在 project.properties.

中设置 dex.force.jumbo=true

这是我的Android清单:

<?xml version="1.0" encoding="UTF-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ag.entega.enetz.promt" android:versionCode="15" android:versionName="1.12">  
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22"/>  
<supports-screens android:smallScreens="false" android:normalScreens="true" android:largeScreens="true"/>  
<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>  
<permission android:name="ag.entega.enetz.promt.permission.C2D_MESSAGE" android:protectionLevel="signature"/>  
<uses-permission android:name="ag.entega.enetz.promt.permission.C2D_MESSAGE"/>  
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>  
<uses-permission android:name="android.permission.WAKE_LOCK"/>  
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>  
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
<uses-permission android:name="android.permission.CAMERA"/>  
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>  
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>  
<uses-feature android:name="android.hardware.wifi"/>  
<application android:label="@string/app_label" android:icon="@drawable/icon" android:allowBackup="false" android:largeHeap="true"> 
    <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>  
    <activity android:name="promt" android:label="@string/app_label" android:configChanges="orientation|keyboardHidden|screenSize" android:launchMode="singleTask" android:theme="@android:style/Theme.Translucent.NoTitleBar" android:screenOrientation="sensor"> 
        <intent-filter> 
            <action android:name="android.intent.action.MAIN"/>  
            <category android:name="android.intent.category.LAUNCHER"/> 
        </intent-filter>  
        <intent-filter> 
            <action android:name="ag.entega.enetz.promt.NOTIFICATION"/>  
            <category android:name="android.intent.category.DEFAULT"/> 
        </intent-filter> 
    </activity>  
    <!-- Preference Activity  -->  
    <activity android:name="com.worklight.common.WLSettingActivity" android:label="Worklight Settings"/>  
    <!-- UI Activity for displaying native dialogs  -->  
    <activity android:name="com.worklight.wlclient.ui.UIActivity"/>  
    <!-- Push service  -->  
    <!-- In order to use the c2dm library, an application must declare a class with the name C2DMReceiver, in its own package, extending com.google.android.c2dm.C2DMBaseReceiver
        It must also include this section in the manifest, replacing "com.google.android.apps.chrometophone" with its package name. -->  
    <service android:name="GCMIntentService"/>  
    <service android:name="ForegroundService"/>  
    <!-- Only google service can send data messages for the app. If permission is not set - any other app can generate it -->  
    <receiver android:name="com.worklight.androidgap.push.WLBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND"> 
        <!-- Receive the actual message -->  
        <intent-filter> 
            <action android:name="com.google.android.c2dm.intent.RECEIVE"/>  
            <category android:name="ag.entega.enetz.promt"/> 
        </intent-filter>  
        <!-- Receive the registration id -->  
        <intent-filter> 
            <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>  
            <category android:name="ag.entega.enetz.promt"/> 
        </intent-filter> 
    </receiver>  
    <activity android:name="com.google.zxing.client.android.CaptureActivity" android:screenOrientation="landscape" android:configChanges="orientation|keyboardHidden" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:windowSoftInputMode="stateAlwaysHidden"> 
        <intent-filter> 
            <action android:name="com.phonegap.plugins.barcodescanner.SCAN"/>  
            <category android:name="android.intent.category.DEFAULT"/> 
        </intent-filter> 
    </activity>  
    <activity android:name="com.google.zxing.client.android.encode.EncodeActivity" android:label="@string/share_name"> 
        <intent-filter> 
            <action android:name="com.phonegap.plugins.barcodescanner.ENCODE"/>  
            <category android:name="android.intent.category.DEFAULT"/> 
        </intent-filter> 
    </activity> 
</application> 

我的问题是:如何解决这个内部 class not found 异常?非常感谢任何帮助。

好的,我知道了。感谢您的所有建议!

首先,我不必要地将 google 播放库包含到我的项目中。它由 Google 推荐并且通常是必需的,但不适用于 MFP。 Mobile First Platform 为游戏带来了一切以使用 GCM 推送通知。但是删除库后,错误仍然出现。

所以我检查了 IBM 的示例项目,对其进行了设置,运行 瞧瞧,当点击通知时应用程序打开了。所以我仔细检查了 AndroidManifest,发现了两个不同之处:

首先,我在应用程序名称前少了一个点 "promt"。所以正确它是“.promt”。

其次,通知的 intent 过滤器缺少 activity 名称:

<intent-filter> 
    <action android:name="ag.entega.enetz.promt.NOTIFICATION"/>  
    <category android:name="android.intent.category.DEFAULT"/> 
</intent-filter> 

必须

<intent-filter> 
    <action android:name="ag.entega.enetz.promt.promt.NOTIFICATION"/>  
    <category android:name="android.intent.category.DEFAULT"/> 
</intent-filter>

修复此问题后不再出现错误,点击通知时应用程序会打开。

因此@IdanAdar 和@Vikin K 指向 AndroidManifest.xml 是正确的。再次感谢大家!

不过,为什么异常没有指向手头的问题,这让我很困惑。