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 是正确的。再次感谢大家!
不过,为什么异常没有指向手头的问题,这让我很困惑。
我最近为我们的一位客户实现了一个基于混合 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 是正确的。再次感谢大家!
不过,为什么异常没有指向手头的问题,这让我很困惑。