Android 应用程序和 Android 库之间的 GCM 冲突
GCM conflict between Android App and Android Library
我正在构建一个使用 GCM 的库。我正在使用同样实现 GCM 的示例应用程序对其进行测试。
除了每个都有自己的发件人 ID 外,我对两者都使用了相同的实现
这就是我为正在测试库的示例应用程序编写的内容。我也为图书馆写了同样的东西,但服务的名称不同:
<!-- GCM -->
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.example.instabug" />
</intent-filter>
</receiver>
<service
android:name=".SampleInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".SampleGcmRegistrationIntentService"
android:exported="false"/>
<service
android:name=".SampleGcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
我的问题是,每当我向我的图书馆发送推送通知时,应用程序接收器总是会捕获它。图书馆接收者什么都不做。
有办法解决这个问题吗?!
据我了解,您有两个具有相同意图过滤器的服务。在这种情况下 Android 将选择优先级更高的服务(前台)。如果优先级相同 - 将随机选择,即只有一项服务会收到意图。
对于您的情况,最佳解决方案是仅使用一项服务并根据 GcmListenerService
.
中 onMessageReceived()
的 from
(senderId) 参数进行调度
我想出了办法做到这一点。在我的 Android 库中,我为 GcmListenerService
的意图过滤器赋予了比 Android 应用程序中更高的优先级,以便库首先接收和处理 GCM 消息。
<service
android:name=".SampleGcmListenerService"
android:exported="false">
<intent-filter priority="100">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
当 GCM 消息到达图书馆的 GcmListenerService
时,如果它与图书馆无关,您必须转发到 android 应用程序。因为我正在制作一个将来任何人都可以使用的库。我不知道在哪里可以找到应用程序模块中的 GcmListenerService
。我所能做的就是使用反射来获取应用程序模块中的所有 classes 并查看哪个具有 GcmListenerService
作为超级 class 然后为那个 [=25] 启动唤醒服务=].
这是我所做的:
@Override
public void onMessageReceived(String from, Bundle data) {
if (!from.equalsIgnoreCase("51XXXXXXXX")) {
String[] classes = getClassesOfPackage(getPackageName());
for (int i = 0; i < classes.length; i++) {
String sClassName = classes[i];
try {
Class classToInvestigate = Class.forName(sClassName);
String superClassName = classToInvestigate.getSuperclass().getName();
if (superClassName.equalsIgnoreCase("com.google.android.gms.gcm.GcmListenerService")) {
//sending intent to the wakeful app's service
forwardGcmToApp(from, data, sClassName);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
//TODO: fire the polling service
String message = data.getString("message");
}
}
/**
* Called to get list of classes included in the current project
*
* @param packageName the name of application package
* @return array of classes' names
*/
private String[] getClassesOfPackage(String packageName) {
ArrayList<String> classes = new ArrayList<>();
try {
String packageCodePath = getPackageCodePath();
DexFile df = new DexFile(packageCodePath);
for (Enumeration<String> iter = df.entries(); iter.hasMoreElements(); ) {
String className = iter.nextElement();
if (className.contains(packageName)) {
classes.add(className);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes.toArray(new String[classes.size()]);
}
/**
* Called to forward Gcm content to the App {@link GcmListenerService}
*
* @param from Gcm sender ID
* @param data bundle received from Gcm
* @param className Class name that extends {@link GcmListenerService}
*/
private void forwardGcmToApp(String from, Bundle data, String className){
Intent intent = new Intent();
intent.setAction("com.google.android.c2dm.intent.RECEIVE");
data.putString("from", from);
data.putString("message_type", null);
intent.putExtras(data);
intent.setComponent(new ComponentName(getPackageName(), className));
GcmReceiver.startWakefulService(getApplicationContext(), intent);
}
我正在构建一个使用 GCM 的库。我正在使用同样实现 GCM 的示例应用程序对其进行测试。
除了每个都有自己的发件人 ID 外,我对两者都使用了相同的实现
这就是我为正在测试库的示例应用程序编写的内容。我也为图书馆写了同样的东西,但服务的名称不同:
<!-- GCM -->
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.example.instabug" />
</intent-filter>
</receiver>
<service
android:name=".SampleInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name=".SampleGcmRegistrationIntentService"
android:exported="false"/>
<service
android:name=".SampleGcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
我的问题是,每当我向我的图书馆发送推送通知时,应用程序接收器总是会捕获它。图书馆接收者什么都不做。
有办法解决这个问题吗?!
据我了解,您有两个具有相同意图过滤器的服务。在这种情况下 Android 将选择优先级更高的服务(前台)。如果优先级相同 - 将随机选择,即只有一项服务会收到意图。
对于您的情况,最佳解决方案是仅使用一项服务并根据 GcmListenerService
.
onMessageReceived()
的 from
(senderId) 参数进行调度
我想出了办法做到这一点。在我的 Android 库中,我为 GcmListenerService
的意图过滤器赋予了比 Android 应用程序中更高的优先级,以便库首先接收和处理 GCM 消息。
<service
android:name=".SampleGcmListenerService"
android:exported="false">
<intent-filter priority="100">
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
当 GCM 消息到达图书馆的 GcmListenerService
时,如果它与图书馆无关,您必须转发到 android 应用程序。因为我正在制作一个将来任何人都可以使用的库。我不知道在哪里可以找到应用程序模块中的 GcmListenerService
。我所能做的就是使用反射来获取应用程序模块中的所有 classes 并查看哪个具有 GcmListenerService
作为超级 class 然后为那个 [=25] 启动唤醒服务=].
这是我所做的:
@Override
public void onMessageReceived(String from, Bundle data) {
if (!from.equalsIgnoreCase("51XXXXXXXX")) {
String[] classes = getClassesOfPackage(getPackageName());
for (int i = 0; i < classes.length; i++) {
String sClassName = classes[i];
try {
Class classToInvestigate = Class.forName(sClassName);
String superClassName = classToInvestigate.getSuperclass().getName();
if (superClassName.equalsIgnoreCase("com.google.android.gms.gcm.GcmListenerService")) {
//sending intent to the wakeful app's service
forwardGcmToApp(from, data, sClassName);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
//TODO: fire the polling service
String message = data.getString("message");
}
}
/**
* Called to get list of classes included in the current project
*
* @param packageName the name of application package
* @return array of classes' names
*/
private String[] getClassesOfPackage(String packageName) {
ArrayList<String> classes = new ArrayList<>();
try {
String packageCodePath = getPackageCodePath();
DexFile df = new DexFile(packageCodePath);
for (Enumeration<String> iter = df.entries(); iter.hasMoreElements(); ) {
String className = iter.nextElement();
if (className.contains(packageName)) {
classes.add(className);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes.toArray(new String[classes.size()]);
}
/**
* Called to forward Gcm content to the App {@link GcmListenerService}
*
* @param from Gcm sender ID
* @param data bundle received from Gcm
* @param className Class name that extends {@link GcmListenerService}
*/
private void forwardGcmToApp(String from, Bundle data, String className){
Intent intent = new Intent();
intent.setAction("com.google.android.c2dm.intent.RECEIVE");
data.putString("from", from);
data.putString("message_type", null);
intent.putExtras(data);
intent.setComponent(new ComponentName(getPackageName(), className));
GcmReceiver.startWakefulService(getApplicationContext(), intent);
}