上周项目的极光推送出问题了,主要是两个问题,第一个为App接收到推送下来的通知后点击状态栏的通知不能跳转。第二个问题为H5页面不能监听到推送下了的通知内容。下面我将分别记录这两个问题的方法。
问题解决
上面两个问题都需要修改ajpush.jar包,这个包主要是提供js端调用极光推送方法的一个桥梁,主要封装了供js端调用的函授,以及接受推送内容的广播类。日常开发如果不反编译是不能直接修改jar包里面的class文,要想修改需要将其转换成.java文件,不过在开发中也是有可以修改第三方代码的小技巧,不需要进行麻烦的反编译。
下面为ajpush.jar包的目录结构,我们看到其实他里面的文件不是很多,所以我们完全可以在自己项目中复制一份完全一样的代码出来进行修改。
具体操作
- 随便点开一个文件查看一下ajpush.jar包的路径。
package com.open.apicloud.jpush;
- 自己项目的com文件夹中也创建一个和上面包名相同的文件夹
- 在文件中创建出和ajpush.jar命名一样的文件(注jar包中的文件类型)
最后经对应文件的代码复制粘贴到我们创建的文件中。
下面是我在自己项目中克隆的ajpush.jar的完整结构:
问题1、点击App状态栏通知不能跳转
在开发中我们根据官方文档在H5页面代码中注册了点击状态栏的跳转事件。
api.addEventListener({
name: 'appintent'
}, function(ret, err) {
if (ret && ret.appParam.ajpush) {
var ajpush = ret.appParam.ajpush;
var id = ajpush.id;
...
}
})
我们看到appintent为事件的名称。其实这个事件已经注册成功了,之所以不能跳转是因为android项目中继承了ExternalActivity这个xxxActivity类在收到通知没有通知js前端调用该事件。还有另外一个原因是xxxActivity类也没有收到极光推送跳转事件发送过来的通知内容。
处理极光推送业务的广播类
为了解决上面问题我们来看一下这个JPushReceiver类,该类继承BroadcastReceiver,用于接受极光推送下来的消息。该类有几个重要的方法
- onReceive():收到消息、通知、点击栏等系统会发出的广播调用该方法。
- performMessage():收到消息后会调用该方法,该方法会将消息内容发送给前段。
- performRegistrationID():注册后会调用该方法,该方法会将消息内容发送给前段。
- performNotification():收到通知后会调用该方法,该方法会将消息内容传给ExternalActivity并将页面跳转到该类。
- transBundleToParam():该方法主要是用来将极光同送下来的数据转换成JSONObject
在onReceive()方法中代码如下:
public void onReceive(Context context, Intent intent) {
if (context != null && intent != null) {
...
if ("cn.jpush.android.intent.REGISTRATION".equals(action)) {
this.performRegistrationID(context, bundle);
} else if ("cn.jpush.android.intent.MESSAGE_RECEIVED".equals(intent.getAction())) {
//接受到消息调用
this.performMessage(context, bundle);
printBundle(bundle);
} else if ("cn.jpush.android.intent.NOTIFICATION_RECEIVED".equals(intent.getAction())) {
//接受通知后调用
printBundle(bundle);
} else if ("cn.jpush.android.intent.NOTIFICATION_OPENED".equals(intent.getAction())) {
//打开App调用
this.performNotification(context, bundle);
printBundle(bundle);
} else if ("cn.jpush.android.intent.ACTION_RICHPUSH_CALLBACK".equals(intent.getAction())) {
...
}
}
}
从上面的代码中我们看到在点击通知后会调用performNotification()方法,主要会执行该方法如下代码:
Intent action = new Intent("android.intent.action.MAIN");
action.addCategory("android.intent.category.LAUNCHER");
action.setComponent(new ComponentName(context, ExternalActivity.class));//跳转的Activity
action.setFlags(805306368);
JSONObject json = this.transBundleToParam(bundle, true, true);//将极光推送送下来的数据转换成JSONObject
action.putExtra("appParam", json.toString());//传递的信息
context.startActivity(action);
从上面的代码可以知道,在点击状态栏推送下来的通知会跳转到ExternalActivity类并将通知内容传递过去。ExternalActivity为使用SuperWebView框架的webview功能必须要继承的类,如果我们想要在自己的TestActivity接受到消息,就要将
action.setComponent(new ComponentName(context, ExternalActivity.class));//跳转的Activity
改为自己的ExternalActivity集成类
action.setComponent(new ComponentName(context, TestActivity.class));//跳转的Activity
最后修改在TestActivity中onNewIntent()方法中接收传递过年来的消息并通知前段调用注册的appintent监听函数
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//接收极光推送的通知内容
String appParam = intent.getStringExtra("appParam");
if (appParam != null) {
try {//通知H5页面调用appintent函数
sendEventToH5("appintent", new JSONObject(appParam));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
问题2、js代码中监听不到通知的内容
下面我们看一下官方提供的官方函数:
var ajpush = api.require('ajpush');
ajpush.setListener(
function(ret) {
var id = ret.id;
...
}
)
该函数官方的说明中并没说不可以监听通知的内容,因此我们JS前端被这个函数和官方说明误导了,以为监听不到通知内容是自己代码写的有问题,结果我们反复查看自己的代码和官方说明也没有找到哪里写错了。最后研究JPushReceiver这个文件的时候才知道上面的函数式是不能监听到通知内容,我们看一下onReceive()方法中的代码
else if ("cn.jpush.android.intent.NOTIFICATION_RECEIVED".equals(intent.getAction())) {
//接受通知后调用
printBundle(bundle);
} else if
...
在接受通知后系统发广播调用了onReceive()方法。经过判断cn.jpush.android.intent.NOTIFICATION_RECEIVED成立,进入该if函数中,但是该函数直到用了打印日志信息的方法,并没有调用performMessage()函数。
注 如果想查看日志信息,需要将JPushReceiver的成员变量
private static boolean debug = false;
设置为true.
为了能使js中setListener()函数能监听到通知内容,我在JPushReceiver中增加了一个成员变量
//用于监听通知,false为信息类型,true为通知类型
private static boolean isNotification = false;
在onReceive()if语句中增加如下代码
...
else if ("cn.jpush.android.intent.NOTIFICATION_RECEIVED".equals(intent.getAction())) {
//接受通知后调用
isNotification = true;
//调用信息发送函数
this.performMessage(context, bundle);
printBundle(bundle);
}
...
最后修改performMessage()代码
private void performMessage(Context context, Bundle bundle) {
logd("performMessage: " + sPushListeners.isEmpty());
JSONObject json;
if (sPushListeners.isEmpty()) {
...
} else {
//isNotificationfalse为消息类型,true为通知类型
json = this.transBundleToParam(bundle, isNotification, false);
Iterator var9 = sPushListeners.iterator();
while (var9.hasNext()) {
JPushListener listener = (JPushListener) var9.next();
//将接受的消息发送到H5页面
listener.onMessage(json);
}
}
isNotification = false;
}
注:通过上面方法测试没有问题之后,别忘了删除libs文件夹下的ajpush.jar包,不然打包的时候回冲突。
总结
由于项目用的是Superwebview+原生的开发方式,以此ApiCloud增加的有些模块需要适配。官方的说明文档只是针对js前段写的,大部分模块没有针对superwebview这种开发模式做特别说明,如果在遇到问题的时候需要认真分析是不是第三方库与superwebview框架适配的问题。