侧边栏壁纸
博主头像
Z同学博主等级

工作磨平激情前,坚持技术的热忱。 欢迎光临Z同学的技术小站。 分享最新的互联网知识。

  • 累计撰写 274 篇文章
  • 累计创建 55 个标签
  • 累计收到 74 条评论

Android 端集成阿里云消息推送

Z同学
2021-11-26 / 0 评论 / 4 点赞 / 578 阅读 / 10,800 字
温馨提示:
本文最后更新于 2021-12-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

主要介绍如何集成阿里云的消息推送服务。以及一些需要注意的要点。

以及一些相关辅助通道的概念介绍。让我们弄懂阿里云消息推送到底是个什么东西

官方说明文档:单纯的推送SDK文档。

https://help.aliyun.com/document_detail/51056.html?source=5176.11533457&userCode=w5jkvc5z

集成方法

我们如果是集成了整个阿里云的emas全部功能: 移动测试,移动热修复,崩溃分析,性能分析,远程日志,消息推送等,建议你直接下载aliyun-emas-services.json 文件,存储到项目之中,采用阿里推荐的方法进行集成。https://help.aliyun.com/document_detail/164998.html#title-7jv-hp5-z2u?source=5176.11533457&userCode=w5jkvc5z 具体文档你可以参考这个进行查询。

我这里只是单纯介绍集成推送的方案:

https://www.aliyun.com/product/cps?source=5176.11533457&userCode=w5jkvc5z

请注意,推送集成是收费的。

image-20211125175133539

介绍

优势

阿里官网介绍的优势:

  • 到达率高:客户试验环境实测高于竞品20-25%;
  • 推送延迟低:客户试验环境实测低于竞品50%;
  • 稳定性高:保障通道容量,业务高峰期保持稳定送达率;
  • 基础设施强:与手淘、高德、优酷等阿里系超级APP使用相同基础设施和技术,享有相同品质;
  • 隐私保护严:坚决捍卫用户隐私数据,绝不从用户数据衍生产品及报告。

限制

最低支持Android 4.1及以上系统。

Android推送服务器在国内,国外可能会存在推送延迟,一般在100~300ms,可以接入辅助使用的Google通道。

推送的消息内容不能超过1800B,就是推送Title+Body <=1800B 。单位转换后就是:不能超过1.8KB。

所以我们要注意消息内容不要太长。

还有推送次数的限制。我们通常集成之后都是后台接口调用阿里提供的OpenAPI进行推消息。

该API也有调用限制。如果批量推送每次最多给1000个设备推送。

全推,也就是给所有用户推送,十分钟内只允许发送10次通知推送。30次消息推送。

下面是官网的描述,我只是按照自己的理解进行了归纳。

image-20211125182015178

基本也能满足我们的推送需求了。问题不大

集成

1.配置maven

在Project根目录build.gradle 项目文件中进行配置:

allprojects {
    repositories {
        jcenter()
        maven {
            url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
        }
        // 配置HMS Core SDK的Maven仓地址。 你如果需要华为辅助通道的话,就加上,否则可以不用加。在下面将会介绍辅助通道的意义。
        maven {
            url 'https://developer.huawei.com/repo/'
        }
    }
}

在你的module 的build.gradle 之中配置NDK

android {
    ......
    defaultConfig {
        applicationId "com.xxx.xxx" //包名 这个包名必须和你在阿里云后台配置的包名一致。
        ......
        ndk {
            //选择要添加的对应cpu类型的.so库。
            abiFilters 'armeabi'
        }
        ......
    }
    ......
}

添加push 的maven库。

//阿里推送库
compile 'com.aliyun.ams:alicloud-android-push:3.7.0' 

//辅助通道基础依赖
implementation 'com.aliyun.ams:alicloud-android-third-push:3.7.0'
//华为依赖
compile 'com.aliyun.ams:alicloud-android-third-push-huawei:3.7.0'
//小米依赖
compile 'com.aliyun.ams:alicloud-android-third-push-xiaomi:3.7.0'
//OPPO依赖
compile 'com.aliyun.ams:alicloud-android-third-push-oppo:3.7.0'
//vivo依赖
compile 'com.aliyun.ams:alicloud-android-third-push-vivo:3.7.0'
//魅族依赖
compile 'com.aliyun.ams:alicloud-android-third-push-meizu:3.7.0'
//谷歌依赖
compile 'com.aliyun.ams:alicloud-android-third-push-fcm:3.7.0'

如果你只使用阿里的渠道进行推送,那么下面的一连串的依赖都可以取消,不用依赖也能实现消息的推送送达。

2.配置AndroidManifest.xml

<application android:name="*****">
		<!--推送库需要的权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <meta-data android:name="com.alibaba.app.appkey" android:value="*****"/> <!-- 请填写你自己的- appKey -->
    <meta-data android:name="com.alibaba.app.appsecret" android:value="****"/> <!-- 请填写你自己的appSecret -->
</application>

在你的主项目下,添加meta-data 参数,分别是appkey,和appsecret。都是在阿里云管理台上可以看到的信息。

你如果不想通过AndroidManifest 进行处理的话,也可以在代码中动态配置

效果:

		// 需要代码动态配置appKey和appSecret
        PushInitConfig config = new PushInitConfig.Builder()
                .application(this)
                .appKey("填入应用的appKey")
                .appSecret("填入应用的appSecret")
                .build();
        PushServiceFactory.init(config);

3.配置Receiver 接收

阿里推送过来的消息是通过广播分发给我们的应用的。所以我们需要注册广播接收对象。

<!-- 消息接收监听器 (用户可自主扩展) -->
<receiver
    android:name=".ZinyanMessageReceiver"
    android:exported="false"> <!-- 为保证receiver安全,建议设置不可导出,如需对其他应用开放可通过android:permission进行限制 -->
    <!--下面结果filter建议不要修改,保持-->
    <intent-filter>
        <action android:name="com.alibaba.push2.action.NOTIFICATION_OPENED" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.alibaba.push2.action.NOTIFICATION_REMOVED" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.alibaba.sdk.android.push.RECEIVE" />
    </intent-filter>
</receiver>

然后我们创建ZinyanMessageReceiver 对象

import com.alibaba.sdk.android.push.MessageReceiver;
import com.alibaba.sdk.android.push.notification.CPushMessage;

public class ZinyanMessageReceiver  extends MessageReceiver {
    // 消息接收部分的LOG_TAG
    public static final String REC_TAG = "receiver";
    @Override
    public void onNotification(Context context, String title, String summary, Map<String, String> extraMap) {
        // TODO 处理推送通知 
        Log.e("MyMessageReceiver", "Receive notification, title: " + title + ", summary: " + summary + ", extraMap: " + extraMap);
        
    }
    @Override
    public void onMessage(Context context, CPushMessage cPushMessage) {
           // TODO 处理推送的消息
            Log.e("MyMessageReceiver", "onMessage, messageId: " + cPushMessage.getMessageId() + ", title: " + cPushMessage.getTitle() + ", content:" + cPushMessage.getContent());
    }
    @Override
    public void onNotificationOpened(Context context, String title, String summary, String extraMap) {
        Log.e("MyMessageReceiver", "onNotificationOpened, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);
    }
    @Override
    protected void onNotificationClickedWithNoAction(Context context, String title, String summary, String extraMap) {
        Log.e("MyMessageReceiver", "onNotificationClickedWithNoAction, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap);
    }
    @Override
    protected void onNotificationReceivedInApp(Context context, String title, String summary, Map<String, String> extraMap, int openType, String openActivity, String openUrl) {
        Log.e("MyMessageReceiver", "onNotificationReceivedInApp, title: " + title + ", summary: " + summary + ", extraMap:" + extraMap + ", openType:" + openType + ", openActivity:" + openActivity + ", openUrl:" + openUrl);
    }
    @Override
    protected void onNotificationRemoved(Context context, String messageId) {
        Log.e("MyMessageReceiver", "onNotificationRemoved");
    }
}

到这里我们的环境和接受对象就全部配置完毕了。

下面我们开始初始化

4.初始化Push SDK

public class ZinyanApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        initCloudChannel(this);
    }
    /**
     * 初始化云推送通道
     */
    private void initCloudChannel(Context applicationContext) {
        PushServiceFactory.init(applicationContext);
        CloudPushService pushService = PushServiceFactory.getCloudPushService();
        pushService.register(applicationContext, new CommonCallback() {
            @Override
            public void onSuccess(String response) {
                Log.d(TAG, "阿里云推送 服务器初始化成功"); 
            }
            @Override
            public void onFailed(String errorCode, String errorMessage) {
                Log.d(TAG, "阿里云推送 服务器初始化失败: 失败代码:" + errorCode + " -- 错误消息:" + errorMessage);
            }
        });
    }
}

调用上面的初始化就可以了。

推送成功后,我们就可以通过

PushServiceFactory.getCloudPushService().getDeviceId()

得到当前设备的DeviceId 了。

这个DeviceId 是阿里云自动生成的。并不是我们自己的账户。然后将该DeviceId给我们的后台进行记录。后面后台推送就直接调用阿里提供的OpenId 接口 传递DeviceId 进行推送了。

我们如果初始化出现了onFailed 怎么办?不用担心,阿里云提供了自动重试。在你切换网络等时机会自动触发。

阿里云推送错误代码:错误处理 (aliyun.com) 你可以通过官网查询错误信息。

5. 延迟初始化-针对隐私政策同意后

现在所有应用都会需要用户同意了隐私政策之后,才会正常往下执行。

pushSDK 也支持这个功能特效。可以调整在政策同意之后再进行推送注册。

PushServiceFactory.init(this) 必须在Application 的OnCreate中进行初始化

但是PushServiceFactory.getCloudPushService().registe() 是可以在之后进行调用的。

不一定必须在Application 的OnCreate方法中进行初始化。

6.NotificationChannel 配置

因为从Android 8.0开始,你如果不配置的话,那么推送消息能够发送到手机上,但是手机顶部状态栏上没有消息提示

public class ZinyanApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        initCloudChannel(this);
        createNotificationChannel()
    }

	private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
            // 通知渠道的id
            String id = "1";
            // 用户可以看到的通知渠道的名字.
            CharSequence name = "notification channel";
            // 用户可以看到的通知渠道的描述
            String description = "notification description";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel mChannel = new NotificationChannel(id, name, importance);
            // 配置通知渠道的属性
            mChannel.setDescription(description);
            // 设置通知出现时的闪灯(如果 android 设备支持的话)
            mChannel.enableLights(true);
            mChannel.setLightColor(Color.RED);
            // 设置通知出现时的震动(如果 android 设备支持的话)
            mChannel.enableVibration(true);
            mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
            //最后在notificationmanager中创建该通知渠道
            mNotificationManager.createNotificationChannel(mChannel);
        }
    }
}

你需要记住上的id 值NotificationChannel ID值。这个值也需要发送给后台小伙伴。他们推送的时候传递该值。手机就能收到状态了。

到这里,手机端的整个集成过程就结束了。

后面就调试能否消息抵达了。

7.动态关闭推送和打开推送

我们如果使用DeviceId 进行绑定推送的话。如果app退出登陆了。不再希望给该设备进行消息推送的话。那么使用方法如下

mPushService = PushServiceFactory.getCloudPushService(); 
//打开推送通道
mPushService.turnOnPushChannel(new CommonCallback() {
      @Override
      public void onSuccess(String s) {
          tvConsoleText.append("推送通到打开\n");
      }

      @Override
      public void onFailed(String errorCode, String errorMsg) {
         tvConsoleText.append("turn on push channel failed." +
                "errorCode: " + errorCode + ", errorMsg:" + errorMsg + "\n");
          }
});
//关闭推送通道
mPushService.turnOffPushChannel(new CommonCallback() {
      @Override
      public void onSuccess(String s) {
          tvConsoleText.append("turn off push channel success\n");
      }
    
      @Override
      public void onFailed(String errorCode, String errorMsg) {
          tvConsoleText.append("turn off push channel failed." +
                "errorCode: " + errorCode + ", errorMsg:" + errorMsg + "\n");
         }
});

//判断推送通道是否打开
mPushService.checkPushChannelStatus(new CommonCallback() {
      @Override
      public void onSuccess(String response) {
          if (response.equals("on")) {
             // 当前是打开状态
          } else {
             // 当前是关闭状态
          }
      }

	  @Override
      public void onFailed(String errorCode, String errorMessage) {
       }
});

绑定账户进行推送

不使用DeviceId 而是使用自有账户进行注册

DeviceId 这个值通常情况下是不变的。什么意思?这个值是阿里sdk 读取手机识别码后生成的唯一码

触发app发生了卸载重装操作,否则默认情况下你跟换账户。两个账户的DeviceId 是一样的。

我们如果不想使用DeviceId ,而是想使用我们自己账户体系的用户ID作为推送设备识别对象。

注意事项:

  • 设备只能绑定一个账号,同一账号可以绑定到多个设备。
  • 同一设备更换绑定账号时无需进行解绑,重新调用绑定账号接口即可生效。
  • 若业务场景需要先解绑后再绑定,在解绑账号成功回调中进行绑定操作,以此保证执行的顺序性。
  • 账号名长度最大支持64字节。
        mPushService = PushServiceFactory.getCloudPushService();
		//绑定  accout 就是我们自己的账户了。
        mPushService.bindAccount(account, new CommonCallback() {
            @Override
            public void onSuccess(String s) {
                tvConsoleText.append("bind account " + account + " success\n");
            }
    
            @Override
            public void onFailed(String errorCode, String errorMsg) {
                tvConsoleText.append("bind account " + account + " failed." +
                        "errorCode: " + errorCode + ", errorMsg:" + errorMsg);
            }
        });
		//取消绑定。如果你需要手动触发的话。那么可以调用该接口进行处理
        mPushService.unbindAccount(new CommonCallback() {
            @Override
            public void onSuccess(String s) {
                tvConsoleText.append("unbind account success\n");
            }

            @Override
            public void onFailed(String errorCode, String errorMsg) {
                tvConsoleText.append("bind account failed." +
                        "errorCode: " + errorCode + ", errorMsg:" + errorMsg + "\n");
            }
        });

辅助通道

我们都知道要想推送消息直达指定的手机,那么手机一定和远程服务器有一个长连接在维持。消息才能够通过这个连接通道发送到手机端。

而要保持长连接,那么一定要调用网络进行访问。就会造成流量和电量的消耗。同时也会有后台服务保持活动状态。

而手机厂商,为了优化。可能就会关闭这些长连接服务。

但是推送又是刚需。所以通常手机厂商会在自家的ROM中做系统级别的推送长连接管理。它收到消息后,再分发给各app处理。

其实苹果就是一个这样的模式。但是Android 由于是开放模式。所以没有统一的标准。

这就是阿里云推送的辅助通道了。

阿里推送默认是使用它自有的推送通道进行推送,如果自有推送通道关闭了,它就会切换到辅助通道进行尝试。

所以:我们如果不开辅助通道,唯一的缺陷就是,app关闭后。手机可能无法收到推送。推送不稳定而已。

阿里的辅助通道集成介绍:

你如果要开通哪个辅助通道,你就需要在厂商指定的开发者平台进行申请相关的key才行了。

错误

针对集成过程中,出现的错误,阿里云上有很丰富的常用错误解决。

[常见问题 (aliyun.com)](https://help.aliyun.com/document_detail/171711.html#Android 端)

我们碰见的大部分问题,上面都有帮助说明。如果没有,那么你可以将错误情况反馈给阿里云。

其他

阿里推送,你如果要测试厂商通道,建议让后台小伙伴配合你使用API接口进行推送。
因为如果我们使用阿里云的后台管理台进行推送的话,貌似它只会走阿里云的自身通道,而不会走厂商通道。

4

评论区