其实阿里推送官网也有自己的sdk。可是他给的demo就一两个方法,其它的都就没有了。项目代码上传到我的 Gitlab aliyun_push上去了,感兴趣的可以下载试试,配置几个参数就可以使用了。
想了想还是自己按照他们的接口自己写重新写一套吧。
在写的过程当中,有个非常小心的地方,时间格式字段,由于没有看清楚,以为 new Date().toISOString();不OK了,那就错了。
new Date().toISOString() 出来的时间,是带毫秒的,他给出的接口里的是不带毫秒的。
第二个就是生成签名,这里要小心就是有一字符要进行转换要不能他就直说签名不正确,于是就封装了一个类。
export default class CommParamService {
constructor() {
this.__InitBaseParams();
}
/**
* 基本参数
*
* @memberof CommParamService
*/
__InitBaseParams() {
this.ParamMap = {};
//--公共参数部分。
this.AddParam('Version', version);
this.AddParam('Format', format);
this.AddParam('AccessKeyId', accessKeyId);
this.AddParam('SignatureMethod', signatureMethod);
this.AddParam('SignatureVersion', signatureVersion);
this.AddParam('SignatureNonce', Utility.generateSerNum()); // 随机数
this.AddParam('Timestamp', new Date().toISOString()); // 时间截
}
/**
* 添加参数
*
* @param {*} key
* @param {*} value
* @memberof CommParam
*/
AddParam(key, value) {
this.ParamMap[key] = value;
return this;
}
/**
* 参数
*
* @param {boolean} [isPop=false]
* @returns
* @memberof CommParam
*/
QueryParams(isPop = false) {
const map = this.ParamMap;
const keys = Object.keys(map).sort();
const keyValues = [];
keys.forEach((key) => {
const _value = !!isPop ? this.ConvertToEscape(map[key]) : encodeURIComponent(map[key]);
keyValues.push(`${key}=${_value}`);
});
const qp = keyValues.join('&');
return qp;
}
/**
* 签名
*
* @memberof CommParam
*/
Signature(Method = 'POST') {
const privateParams = this.ConvertToEscape(this.QueryParams(true));
const stringToSign = `${Method.toUpperCase()}&${encodeURIComponent('/')}&${privateParams}`;
const sign = crypto.createHmac('sha1', `${secretAccessKey}&`.toString('utf-8'))
.update(stringToSign.toString('utf-8'))
.digest()
.toString('base64');
this.AddParam('Signature', sign);
return sign;
}
/**
* 值转换
*
* @param {*} value
* @returns
* @memberof CommParam
*/
ConvertToEscape(value) {
return encodeURIComponent(value)
.replace(/\!/gi, '%21')
.replace(/\'/gi, '%27')
.replace(/\(/gi, '%28')
.replace(/\)/gi, '%29')
.replace(/\*/gi, '%2A');
}
}
如果要调用怎么呢?在另一个AliyunService里写一个方法如给iOS推送。
export default class AliYunService {
async __SendMsg({ cps, }) {
cps.Signature();
const urlParam = cps.QueryParams();
Utility.printLog(cps.ParamMap, '\r\n', urlParam);
const result = await HttpHelper.onApiPost(PushUrl, { data: urlParam, headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' } });
return result;
}
/**
* 推通知给iOS设备
*
* @returns
* @memberof AliYunService
*/
async PushNoticeToiOS(params = {}) {
const cp = new CommParamService();
cp.AddParam('Action', 'PushNoticeToiOS')
.AddParam('ApnsEnv', apnsEnv || 'DEV')
.AddParam('Target', 'ACCOUNT') // 指定帐号,用的是用户ID。
.AddParam('TargetValue', 'user_account_id')
.AddParam('Title', '测试通知标题')
.AddParam('ExtParameters', JSON.stringify({ url: 'http://m.yfarm.net/#app/home' }))
.AddParam('Body', `终于成功啦${Utility.formatDate(new Date().getTime())}`);
return await this.__SendMsg({ cps: cp });
}
}
到这里阿里App的核心功能就基本上OK了。ios或android基本上就能接到推送消息了。
这里有个小小的问题,那就是十几个接口,能不能合到一个方法里来实现呢,参数是外面传进入你要调用哪个方法。
然后每个接口需要的参数与传的参数进行匹配上。合完之后方法代码如下:
/**
* 发送推送
*
* @param {*} params
* @returns
* @memberof AliYunService
*/
async SendPush(params) {
const { Action } = params;
const { Api } = this.AliPushApiMap();
const { Input } = Api[Action];
if (!Input) {
Utility.throwClientError({ msg: `【${Action}】方法没有找到。` })
}
const cps = new CommParamService();
cps.AddParam('Action', Action);
const keys = Object.keys(Input);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
const { Required, Type, Desc, Default } = Input[key];
const _value = params[key];
// Utility.printLog(key, _value, Default);
if (Required) {
if (Type === TypeMap.Boolean) {
if (Utility.isBoolean(_value)) {
cps.AddParam(key, _value);
} else if (Utility.isBoolean(Default)) {
cps.AddParam(key, Default);
} else {
Utility.throwClientError({ msg: `${key} 不能为空:${Desc}` });
}
} else if (Type === TypeMap.DateTimeByISO601) {
if (!_value) {
Utility.throwClientError({ msg: `${key} 不能为空:${Desc}` });
} else {
cps.AddParam(key, _value.toISOString().replace(/\.\d\d\d/g, '')); // 去掉毫秒。
}
} else if (_value) {
cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(_value) : _value);
} else if (Default) {
cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(Default) : Default);
} else {
Utility.throwClientError({ msg: `${key} 不能为空:${Desc}` });
}
} else {
if (Type === TypeMap.Boolean) {
if (Utility.isBoolean(Default)) {
cps.AddParam(key, Default);
}
} else if (_value) {
cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(_value) : _value);
} else if (Default) {
cps.AddParam(key, Type === TypeMap.Object ? JSON.stringify(Default) : Default);
}
}
}
return await this.__SendMsg({ cps });
}
然后想调用哪个只要配置上就OK了。