写在前面:
之前使用阿里云的服务器用阿里消息推送好好的,然后因为国外业务需要使用亚马逊服务器,阿里云推送也不能用,用亚马逊的 SNS (短信消息推送服务),SNS 可以对接多家推送平台,其中 Android 的有 FCM 和百度云两家。FCM 是谷歌亲儿子但是没梯子进不来,百度国内可以用但是国外又出不去。出于这个原因两个推送都接入了。如果说单独接入百度推送或者FCM都是简单的事情。主要是接入亚马逊的SNS文档全是英文不说还描述不清楚,网上搜索到的资料又零零散散,所以将这次接入流程记录下来。
一、单渠道接入
百度云推送官方文档 百度云推送需要先创建应用这些资料都是比较好找的不做赘述。创建成功后主要提供这些参数给到亚马逊。客户端密钥就是对应的SECRET KEY
FCM官方文档 流程很清晰,感觉比百度的接入更加方便,不需要配置.so库啥的。创建应用啥的,创建完需要提供API密钥。其实就是图下的云消息传递中的服务器密钥。
二、接入SNS
到这里认为您的推送集成成功,在百度云/FCM自己的控制台测试推送没问题的前提下。准备将我们的设备与SNS连接起来。最主要的就是创建端点,然后将端点信息交给服务器。Android端需要引入SNS相关的包(当前最新版本)
implementation 'com.amazonaws:aws-android-sdk-sns:2.6.20'
百度云推送创建端点需要token和UserId两个属性,这两个参数再百度云推送服务绑定成功的时候会获取到。在官方代码里面属于拓展属性没有专门的方法添加,需要通过withAttributes()这个方法进行添加参数。FCM可以不用这个方法而是直接通过withToken()将FCM的onNewToken获取到的token传过去。同时也可以进行主题的订阅但是这里注释掉了,有需要可以放开。创建的端点信息需要交给服务器,服务器再做对应的推送。至于怎么给那就是前后端自己约定的事情了。创建端点成功后在亚马逊服务器后台就能看到了。
fun createBaiduEndpoint(userId:String?,token: String): String? {
Log.e(PushMessageReceiver.TAG, "sendTokentoSNS: ")
userId?:return null
val access_id = "你的亚马逊access_id"
val secret_key = "你的亚马逊secret_key"
val appArn = "亚马逊创建的应用的ARN"
// val topicArn= "亚马逊创建的应用的主题的ARN"
val credentials: AWSCredentials = BasicAWSCredentials(access_id, secret_key)
val provider: AWSCredentialsProvider = StaticCredentialsProvider(credentials)
val snsClient = AmazonSNSClient(provider)
snsClient.setRegion(Region.getRegion(Regions.EU_WEST_1))
var endpointArn: String? = null
endpointArn = try {
println("Creating platform endpoint with token $token")
//百度云推送在绑定的时候会返回的参数userId和channeId
val mutableMapOf = mutableMapOf<String, String>()
mutableMapOf["UserId"]=userId
mutableMapOf["ChannelId"]=token
val cpeReq = CreatePlatformEndpointRequest()
.withPlatformApplicationArn(appArn)
.withToken(token)
.withAttributes(mutableMapOf)//百度需要FCM不用
val cpeRes: CreatePlatformEndpointResult = snsClient
.createPlatformEndpoint(cpeReq)
// val subscribeRequest: SubscribeRequest = SubscribeRequest()
// .withProtocol("application")
// .withTopicArn(topicArn)
// .withEndpoint(result.endpointArn)
// snsClient.subscribe(subscribeRequest)
return cpeRes.endpointArn
} catch (ipe: InvalidParameterException) {
val message: String = ipe.getErrorMessage()
ipe.printStackTrace()
val p: Pattern = Pattern
.compile(
".*Endpoint (arn:aws:sns[^ ]+) already exists " +
"with the same [Tt]oken.*"
)
val m: Matcher = p.matcher(message)
if (m.matches()) {
// The platform endpoint already exists for this token, but with
// additional custom data that
// createEndpoint doesn't want to overwrite. Just use the
// existing platform endpoint.
m.group(1)
} else {
// Rethrow the exception, the input is actually bad.
throw ipe
}
}
return endpointArn
}
写在后面:
文章技术含量一点没有,主要是苦于网上没有一套完整的资料,我甚至连怎么引入依赖都百度了好久。上面的代码有些甚至于来自git上ruby端的issue通过自己的猜测写出来的。网上相对较多的还是有相关FCM(GCM)接入SNS的,我也主要借鉴于AWS SNS+Google FCM推送服务的使用这篇博客,稍稍可惜的是并没有讲如何引入依赖。但是关于百度接入SNS的简直凤毛麟角。写在这里方便自己以后回顾也希望能让别人少踩这样的坑。