最近需要使用到华为push,就研究了一下。但是上网搜索了,都说,华为push是一个大坑。我暂且不说遇到的坑,只是说,最基础的集成。我是用的IDE是Android Studio,这里只讲解有关于Android Studio的集成方式,Eclipse大神请绕步。
首先要注册一个账号,进入华为开发者联盟官网, 点击管理中心。
然后进入管理中心页面,我们在选择push服务
我们进入到了push页面,我们就可以做一些操作了。首先创建一个应用。
点击申请push服务,我们可以看到,创建应用时需要写一些信息。
按照自己的项目进行选择创建。需要注意的一点是,我们发现他需要的SHA256证书指纹可以有多个,是因为。你的项目有可能会有多个指纹证书,都可以写在上面。这个SHA256证书指纹不能填写DeBug模式下的指纹。需要的是release模式下的指纹证书。所以,我们需要先进行apk打包。这里我就不多讲述了。
获取SHA256指纹证书我说一下吧。
首先打开cmd命令窗口。找到我们的keystore文件。也就是jks文件,输入命令keytool -list -v -keystore 你的jks文件名.jks
如果输入成功按下回车,会让你输入密码,但是输入密码时是无状态的,就输入生成jks文件的密码就行。然后你就能得到你的SHA256证书指纹了。
完成以上才是完成了第一步,在平台创建应用。
下面再看华为文档。不得不说,如果一步一步按文档集成还是很靠谱的,就是有时候,你不知道它想表达些什么,可能我理解能力有限,嘿嘿。我们先下载文档提供的SDK。SDK入口随处可见,在你的PUSH页面,创建好的应用上方有几个选项,我们选择SDK下载。会发现,进入了消息推送服务文档中心。我们就根据文中心,一步一步的集成华为push。
先下载SDK,这里是新版SDK,由于旧版的不在维护,我们就不做集成讲解。
下载过后,你会得到一个HMSAgent_2.6.3.301文件夹,打开它
你会看到这么几个文件。点击运行GetHMSAgent_cn.bat程序,根据提示一步一步集成
首先输入包名,包名在你的AndroidManifest.xml文件中就能得到。appid是你在华为push服务平台上创建的应用的appid
cpid,我们可以不用填,那是在集成游戏和支付时,才会使用到的。
我们只需要集成push服务,其它的都选择0就可以,按任意键结束后,打开copysrc文件夹。一直往里点,我们会得到如下文件。
这就是我们所需要的PUSH服务SDK了。将其copy到我们的工程中去,由于位置不同,我们需要再我们的项目中,将这些文件中的导包路径修改一下,是个体力活。
修改完成,确认无报错的情况下,我们再看文档。
我们还需要在我们的IDE里面添加仓库路径,我使用的是Android Studio。Eclipse我暂时还没有使用。
在项目的gradle里面写上如上路径
在app.gradle里填写依赖
dependencies {
compile 'com.huawei.android.hms:push:{version}'
}
说明:{version} 替换为实际的版本号,如:compile 'com.huawei.android.hms:push:2.6.3.301'
更多在往下看有接入准备、开发准备、开发指南。都有详细的集成开发说明。
我们是做Android的,所以进入客户端开发指南,服务端请移步服务端开发指南。
首先会进行一个功能说明,我们往下看,会看到一个新旧版本的SDK对比。我说过,它的旧版的SDK已不在维护,我就不多做讲解了。还能看到华为PUSH支持的国家和地区。因为它是华为提供的push服务,在其它品牌的手机上无法使用。它只支持emui4.1以上的版本。其它的它不支持。再往下看就是正文了。
注:以下均为华为push推送服务客户端开发指南文档资料。
第一步,初始化Agent。
1.1 调用init接口
在application的onCreate方法中初始化HMSAgent。如果没有自己的application类,请创建并在manifest文件中配置application节点的name属性。
示例代码如下:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
HMSAgent.init(this);
}
}
1.2 调用connect接口
建议在应用启动时调用Connect。
示例代码如下:
HMSAgent.connect(this, new ConnectHandler() {
@Override
public void onConnect(int rst) {
showLog("HMS connect end:" + rst);
}
});
第二步 申请Push token
2.1 场景介绍
通过调用getToken接口向服务端请求应用的唯一标识——Device Token,Push服务端根据这个token发送推送消息。每个设备的上每个应用的Token都是唯一存在。您可以在自定义广播中的onToken方法接收返回的token字符串,并且将token上报到自己的应用服务器维护这些已申请的token列表,然后调用Push服务器的推送消息接口,根据token批量推送消息。
2.2受限说明
getToken接口只有在服务端开通了Push服务申请token才会返回成功。目前仅中国区和部分海外地区支持开通push服务
目前华为推送支持的地区有(支持的地区后期可能有所增加):
中国大陆,泰国, 越南 ,中国香港 ,中国台湾 ,柬埔寨 斯里兰卡,印度,中国澳门,新加坡,马来西亚,澳大利亚,新西兰,菲律宾,印度尼西亚,孟加拉国。
约旦,埃及,阿尔及利亚,马里,也门,乍得,塞内加尔,突尼斯,阿拉伯联合酋长国,阿曼,巴基斯坦,巴林,卡塔尔,科威特,沙特阿拉伯,伊拉克。
墨西哥,委内瑞拉,哥伦比亚,厄瓜多尔,危地马拉,尼加拉瓜,萨尔瓦多,洪都拉斯,哥斯达黎加,巴拿马,多米尼加共和国,牙买加,波多黎各,阿根廷,玻利维亚,巴拉圭,秘鲁,乌拉圭,智利。
南非,卢旺达,安哥拉,博茨瓦纳,布隆迪,津巴布韦,肯尼亚,马达加斯加,马拉维,毛里求斯,坦桑尼亚,乌干达,赞比亚,尼日利亚,加纳,喀麦隆,象牙海岸,刚果(金)。
阿尔巴尼亚,奥地利,比利时,荷兰,葡萄牙,挪威,爱尔兰,意大利,法国,德国,西班牙,瑞典,英国,芬兰,希腊,冰岛,波兰,罗马尼亚,塞尔维亚,斯洛文尼亚,斯洛伐克,黑山,克罗地亚,保加利亚,列支敦士登,卢森堡,马耳他,科索沃,拉脱维亚,丹麦,爱沙尼亚,立陶宛,波斯尼亚和黑塞哥维那,匈牙利,马其顿,摩尔多瓦,捷克共和国,塞浦路斯。
注意:getToken接口在非中国区发货设备或非华为手机上首次调用时,会显示华为Push用户协议条款界面(如下图)。建议在Activity页面里再调用getToken接口。
中国区发货的华为设备不会显示该协议条款界面。
2.3 业务流程
2.4 开发步骤
申请token会触发启动Push服务,token申请成功后,结果会通过广播的方式返回token给应用。调用getToken方法发起请求,返回申请token的PendingResult对象,根据对象可以获取接口调用是否成功,但是不直接返回token 结果。
接口详细定义请参见getToken,申请token的示例代码如下:
/**
* 获取token
*/
private void getToken() {
showLog("get token: begin");
HMSAgent.Push.getToken(new GetTokenHandler() {
@Override
public void onResult(int rtnCode, TokenResult tokenResult) {
showLog("get token: end" + rtnCode);
}
});
}
调用getToken接口后通过广播接收token值
下面的示例代码实现如何处理onToken接口来获取push token。CP需要将token妥善的保存起来。如果CP自己实现了调用华为PUSH服务器端接口发送推送消息,那么可以推送消息到指定的Token用户。如果有涉及到在客户端和服务器之前传输Token,请确保Token的安全。
public class HUAWEIPushRevicer extends PushReceiver {
@Override
public void onToken(Context context, String token, Bundle extras) {
}
}
3 注销 token
3.1 场景介绍
应用调用注销TOKEN接口成功之后,客户端就不会再接收到PUSH消息。
3.2 受限说明
建议APP集成时暂时不要依赖deleteToken接口;如果应用要实现注销TOKEN后不接收PUSH消息,需要自行上报失效TOKEN到应用自己的服务器,并且在推送消息时判断是失效TOKEN就不进行推送。
注意:该接口只在华为手机并且EMUI版本号不低于5.1的版本上才起作用,即只在EMUI5.1以及更高版本的华为手机上调用该接口后才不会收到PUSH消息。
在非华为手机上则必须满足HMS版本不低于2.5.0。
3.3 开发步骤
调用注销token接口,实现注销token的示例代码如下:
/**
* 删除token | delete push token
*/
private void deleteToken(){
showLog("deleteToken:begin");
HMSAgent.Push.deleteToken(token, new DeleteTokenHandler() {
@Override
public void onResult(int rst) {
showLog("deleteToken:end code=" + rst);
}
});
}
4 获取push连接状态
4.1 场景介绍
查看Push通道是否已连接,结果会通过自定义广播里的onPushState方法返回。
4.2 受限说明
此接口在之后的版本中会逐渐废弃,请业务谨慎使用。
4.3 开发步骤
4.3.1 调用查询Push连接状态接口
实现查询PUSH连接状态的示例代码如下:
/**
* 获取push状态 | Get Push State
*/
private void getPushStatus() {
showLog("getPushState:begin");
HMSAgent.Push.getPushState(new GetPushStateHandler() {
@Override
public void onResult(int rst) {
showLog("getPushState:end code=" + rst);
}
});
}
4.3.2 通过广播接收Push连接状态
下面的代码示例代码实现如何处理onPushState接口。
当push处于连接状态的时候,才能正常接收push消息。
public class HuaweiPushRevicer extends PushReceiver {
private static final String TAG = "HuaweiPushRevicer";
public static final String ACTION_UPDATEUI = "action.updateUI";
public static final String ACTION_TOKEN = "action.updateToken";
private static List<IPushCallback> pushCallbacks = new ArrayList<IPushCallback>();
private static final Object CALLBACK_LOCK = new Object();
public interface IPushCallback {
void onReceive(Intent intent);
}
public static void registerPushCallback(IPushCallback callback) {
synchronized (CALLBACK_LOCK) {
pushCallbacks.add(callback);
}
}
public static void unRegisterPushCallback(IPushCallback callback) {
synchronized (CALLBACK_LOCK) {
pushCallbacks.remove(callback);
}
}
@Override
public void onToken(Context context, String tokenIn, Bundle extras) {
String belongId = extras.getString("belongId");
Intent intent = new Intent();
intent.setAction(ACTION_TOKEN);
intent.putExtra(ACTION_TOKEN, tokenIn);
callBack(intent);
intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "belongId is:" + belongId + " Token is:" + tokenIn);
callBack(intent);
}
@Override
public boolean onPushMsg(Context context, byte[] msg, Bundle bundle) {
try {
//CP可以自己解析消息内容,然后做相应的处理 | CP can parse message content on its own, and then do the appropriate processing
String content = new String(msg, "UTF-8");
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "Receive a push pass message with the message:" + content);
callBack(intent);
} catch (Exception e) {
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "Receive push pass message, exception:" + e.getMessage());
callBack(intent);
}
return false;
}
public void onEvent(Context context, Event event, Bundle extras) {
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
int notifyId = 0;
if (Event.NOTIFICATION_OPENED.equals(event) || Event.NOTIFICATION_CLICK_BTN.equals(event)) {
notifyId = extras.getInt(BOUND_KEY.pushNotifyId, 0);
if (0 != notifyId) {
NotificationManager manager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notifyId);
}
}
String message = extras.getString(BOUND_KEY.pushMsgKey);
intent.putExtra("log", "Received event,notifyId:" + notifyId + " msg:" + message);
callBack(intent);
super.onEvent(context, event, extras);
}
@Override
public void onPushState(Context context, boolean pushState) {
Intent intent = new Intent();
intent.setAction(ACTION_UPDATEUI);
intent.putExtra("log", "The Push connection status is:" + pushState);
callBack(intent);
}
private static void callBack(Intent intent) {
synchronized (CALLBACK_LOCK) {
for (IPushCallback callback : pushCallbacks) {
if (callback != null) {
callback.onReceive(intent);
}
}
}
}
}
集成如上,基本上就ok了。注意,你需要安装release类型的apk才行,因为你的keystore证书指纹是release类型的。
可以查看push连接状态,根据返回的结果码判断是否成功集成。查看错误通用码。返回0说明连接成功了,可以自己试着去平台发送一条信息试一下。token是你的广播的onToken方法返回的,需要稍等片刻才能看到,毕竟心急吃不了热豆腐嘛,嘿嘿。