提交 b0121dfd 编写于 作者: taohebin@dcloud.io's avatar taohebin@dcloud.io

feat: unipush

上级 0c6c9a4f
{
"id": "uni-push",
"displayName": "uni-push",
"version": "1.0.0",
"description": "uni-push",
"keywords": [
"uni-push"
],
"repository": "",
"engines": {
"HBuilderX": "^3.6.8"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "",
"data": "",
"permissions": ""
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"uni-ext-api": {
"uni": {
"getPushClientId": {
"name": "getPushClientId",
"app": {
"js": false,
"kotlin": true,
"swift": false
}
},
"onPushMessage": {
"name": "onPushMessage",
"app": {
"js": false,
"kotlin": true,
"swift": false
}
},
"offPushMessage": {
"name": "offPushMessage",
"app": {
"js": false,
"kotlin": true,
"swift": false
}
},
"getChannelManager": {
"name": "getChannelManager",
"app": {
"js": false,
"kotlin": true,
"swift": false
}
},
"createPushMessage": {
"name": "createPushMessage",
"app": {
"js": false,
"kotlin": true,
"swift": false
}
}
}
},
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "u",
"aliyun": "u"
},
"client": {
"Vue": {
"vue2": "u",
"vue3": "u"
},
"App": {
"app-android": "u",
"app-ios": "u"
},
"H5-mobile": {
"Safari": "u",
"Android Browser": "u",
"微信浏览器(Android)": "u",
"QQ浏览器(Android)": "u"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
\ No newline at end of file
# uni-push
`uni-push` 工程,是基于 DCloud-UTS 架构之上的封装个推消息推送 `SDK` 的插件工程,使用此模块可轻松实现服务端向客户端推送通知和透传消息的功能。
### 插件使用说明
#### 导入插件
```uts
import * as GTPlugin from "../../uni_modules/uni-push"
```
#### 初始化
```typescript
//初始化个推推送
GTPlugin.initPush();
```
#### 推送消息事件
> 添加透传消息回调,对应的GTPlugin.offPushMessage()可移除对应监听callback(传入null,可移除所有监听callback)
```typescript
GTPlugin.onPushMessage((res) => {
console.log("onPushMessage => " + JSON.stringify(res))
})
```
| 名称 | 类型 | 描述 |
| ---- | ------------- | ----------------------------------------------------------- |
| type | String | 事件类型,"click"-从系统推送服务点击消息启动应用事件;"receive"-应用从推送服务器接收到推送消息事件。 |
| data | String、Object | 消息内容 |
#### 日志
开发阶段,需要使用到日志辅助。
```typescript
//设置日志回调,可以在控制台看到[GT-PUSH]的日志
GTPlugin.setDebugLogger(function(res) {
console.log(res)
});
```
当插件正常初始化会出现以下日志:
```uts
16:47:53.254 [GT-PUSH] [LogController] Sdk version = 3.3.0.0 at pages/index/index.vue:25
16:47:54.052 [GT-PUSH] [ServiceManager] ServiceManager start from initialize... at pages/index/index.vue:25
16:47:54.073 [GT-PUSH] PushCore started at pages/index/index.vue:25
16:47:54.274 [GT-PUSH] onHandleIntent() = get sdk service pid at pages/index/index.vue:25
16:47:54.292 [GT-PUSH] onHandleIntent() areNotificationsEnabled at pages/index/index.vue:25
16:47:54.353 [GT-PUSH] [LoginInteractor] Start login appid = nU*******wzf at pages/index/index.vue:25
16:47:54.571 收到 cid onReceiveClientId : 3061f********ce7578eb24 at pages/index/index.vue:29
16:47:54.592 [GT-PUSH] onHandleIntent() = received client id at pages/index/index.vue:25
16:47:54.593 [GT-PUSH] [LoginResult] Login successed with cid = 3061f********ce7578eb24 at pages/index/index.vue:25
```
#### 推送相关动作
> 设置推送相关动作回调,更多可查看`app-android/index.uts`下面的 `UserPushAction`类
```typescript
GTPlugin.setPushAction({
onReceiveClientId: function(cid) {
console.log("收到 cid onReceiveClientId : " + cid)
}
});
```
#### 唯一的推送标识
获取客户端唯一的推送标识
```typescript
GTPlugin.getPushClientId({
success: (res) => {
console.log("getPushClientId success => " + JSON.stringify(res));
},
fail: (res) => {
console.log("getPushClientId fail => " + JSON.stringify(res));
},
complete: (res) => {
console.log("getPushClientId complete => " + JSON.stringify(res));
}
});
```
**OBJECT 参数说明**
| 参数名 | 类型 | 必填 | 说明 |
| -------- | -------- | --- | ------------------------ |
| success | Function | 是 | 接口调用的回调函数,详见返回参数说明 |
| fail | Function | 否 | 接口调用失败的回调函数 |
| complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
**success 返回参数说明**
| 参数 | 类型 | 说明 |
| ------ | ------ | ---------------------------------------- |
| cid | String | 个推客户端推送id,对应uni-id-device表的push_clientid |
| errMsg | String | 错误描述 |
**fail 返回参数说明**
| 参数 | 类型 | 说明 |
| ------ | ------ | ---- |
| errMsg | String | 错误描述 |
### APP_ID申请
可登录[个推官网](https://dev.getui.com/)注册申请应用,获取APP相关信息。
### 多厂商
多厂商渠道可以参考[[厂商应用开通指南-个推文档中心](https://docs.getui.com/getui/mobile/vendor/vendor_open/)[厂商 SDK 集成指南-个推文档中心](https://docs.getui.com/getui/mobile/vendor/androidstudio/)
> 注意:华为厂商需要把`agconnect-services.json` 放到${工程根目录}/nativeResources/android/ 目录下
### 开发文档
[个推推送SDK](https://docs.getui.com/getui/start/accessGuide/)
[多厂商接入](https://docs.getui.com/getui/mobile/vendor/vendor_open/)
### 注意事项
`AndroidManifest.xml`中,必须声明插件`flag`
```xml
<!-- 标识dcloud -->
<meta-data android:name="GETUI_PLUGIN_FLAG" android:value="dcloud"/>
```
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
package="uts.sdk.modules.uniPush">
<application>
<activity android:name="io.dcloud.uniapp.UniAppActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="io.dcloud.unipush" android:path="/" android:scheme="unipush" />
</intent-filter>
</activity>
<!-- 如果插件中注册组件时, 包名应为: `uts.sdk.modules.uniPush.PushActionService` , 但由于此插件是内部插件, 所以包名改为: `uts.sdk.modules.DCloudUniPush.PushActionService` -->
<service android:name="uts.sdk.modules.DCloudUniPush.PushActionService" android:exported="false" />
<meta-data android:name="GETUI_APPID" android:value="${GETUI_APPID}" />
<meta-data android:name="MIPUSH_APPID" android:value="XM_${MIPUSH_APPID}" />
<meta-data android:name="MIPUSH_APPKEY" android:value="XM_${MIPUSH_APPKEY}" />
<meta-data android:name="MEIZUPUSH_APPID" android:value="MZ_${MEIZUPUSH_APPID}" />
<meta-data android:name="MEIZUPUSH_APPKEY" android:value="MZ_${MEIZUPUSH_APPKEY}" />
<meta-data android:name="OPPOPUSH_APPKEY" android:value="OP_${OPPOPUSH_APPKEY}" />
<meta-data android:name="OPPOPUSH_APPSECRET" android:value="OP_${OPPOPUSH_APPSECRET}" />
<meta-data android:name="com.huawei.hms.client.appid" android:value="${com.huawei.hms.client.appid}" />
<meta-data android:name="com.vivo.push.app_id" android:value="${com.vivo.push.app_id}" />
<meta-data android:name="com.vivo.push.api_key" android:value="${com.vivo.push.api_key}" />
<meta-data android:name="dcloud_unipush_auto_notification" android:value="${dcloud_unipush_auto_notification}" />
</application>
</manifest>
\ No newline at end of file
{
"parameters": {
"appid": {
"placeholder": "GETUI_APPID"
},
"mipush_appid": {
"placeholder": "MIPUSH_APPID"
},
"mipush_appkey": {
"placeholder": "MIPUSH_APPKEY"
},
"meizupush_appid": {
"placeholder": "MEIZUPUSH_APPID"
},
"meizupush_appkey": {
"placeholder": "MEIZUPUSH_APPKEY"
},
"oppopush_appkey": {
"placeholder": "OPPOPUSH_APPKEY"
},
"oppopush_appsecret": {
"placeholder": "OPPOPUSH_APPSECRET"
},
"huaweipush_appid": {
"placeholder": "com.huawei.hms.client.appid"
},
"vivopush_appid": {
"placeholder": "com.vivo.push.app_id"
},
"vivopush_appkey": {
"placeholder": "com.vivo.push.api_key"
},
"dcloud_unipush_auto_notification": {
"placeholder": "dcloud_unipush_auto_notification"
}
},
"files": [{
"source": "push_unipush_huaweipush_agconnect-services.json",
"target": "agconnect-services.json",
"des": "HMS配置文件"
}]
}
\ No newline at end of file
import Context from "android.content.Context";
import GTPlugin from "com.getui.sdk.GTPlugin";
import IPushAction from "com.getui.sdk.IPushAction";
import GTCmdMessage from "com.igexin.sdk.message.GTCmdMessage";
import GTNotificationMessage from "com.igexin.sdk.message.GTNotificationMessage";
import GTTransmitMessage from "com.igexin.sdk.message.GTTransmitMessage";
import IUserLoggerInterface from "com.igexin.sdk.IUserLoggerInterface";
export function gtInit(context : Context) : void {
GTPlugin.initialize(context);
}
export function getClientId(context : Context) : string {
return GTPlugin.getClientId(context);
}
export function setPushAction(action : UserPushAction) : void {
GTPlugin.setPushAction(action);
}
export type GTPushActionOptions = {
onReceiveServicePid ?: (res : number) => void
/**
* 接收clientId(cid)
*/
onReceiveClientId ?: (res : string) => void
/**
* 此方法用于接收和处理透传消息。透传消息个推只传递数据,不做任何处理,客户端接收到透传消息后需要自己去做后续动作处理,如通知栏展示、弹框等。
* 如果开发者在客户端将透传消息创建了通知栏展示,建议将展示和点击回执上报给个推。
*/
onReceiveMessageData ?: (res : string) => void
/**
* cid 离线上线通知
*/
onReceiveOnlineState ?: (res : boolean) => void
/**
* 各种事件处理回执
*/
onReceiveCommandResult ?: (res : GTCmdMessage) => void
/**
* 通知点击,只有个推通道下发的通知会回调此方法
*/
onNotificationMessageClicked ?: (res : string) => void
/**
* 通知到达,只有个推通道下发的通知会回调此方法
*/
onNotificationMessageArrived ?: (res : GTNotificationMessage) => void
}
export class UserPushAction implements IPushAction {
constructor(
private options : GTPushActionOptions) {
}
override onReceiveServicePid(ctx : Context, pid : Int) {
this.options.onReceiveServicePid?.(pid)
}
/**
* 接收clientId(cid)
*/
override onReceiveClientId(ctx : Context, cid : string) {
this.options.onReceiveClientId?.(cid)
}
/**
* 此方法用于接收和处理透传消息。透传消息个推只传递数据,不做任何处理,客户端接收到透传消息后需要自己去做后续动作处理,如通知栏展示、弹框等。
* 如果开发者在客户端将透传消息创建了通知栏展示,建议将展示和点击回执上报给个推。
*
* class GTTransmitMessage {
* private String taskId;
* private String messageId;
* private String payloadId;
* private byte[] payload;
* }
*/
override onReceiveMessageData(ctx : Context, message : GTTransmitMessage) {
this.options.onReceiveMessageData?.(new String(message.getPayload()))
}
/**
* cid 离线/上线通知
*/
override onReceiveOnlineState(ctx : Context, state : boolean) {
this.options.onReceiveOnlineState?.(state)
}
/**
* 各种事件处理回执
*/
override onReceiveCommandResult(ctx : Context, message : GTCmdMessage) {
this.options.onReceiveCommandResult?.(message)
}
/**
* 通知点击,只有个推通道下发的通知会回调此方法
*/
override onNotificationMessageClicked(ctx : Context, message : GTNotificationMessage) {
const params = {
"title": message.getTitle(),
"content": message.getContent()
};
this.options.onNotificationMessageClicked?.(JSON.stringify(params))
}
/**
* 通知到达,只有个推通道下发的通知会回调此方法
*/
override onNotificationMessageArrived(ctx : Context, message : GTNotificationMessage) {
this.options.onNotificationMessageArrived?.(message)
}
}
class UserLoggerInterface implements IUserLoggerInterface {
constructor(private callback : (log : string) => void) {
}
override log(s : string) {
this.callback?.(s)
}
}
/**
* 个推推送sdk调试日志信息
* setDebugLogger 接口仅限调试的时候使用,切勿发布到线上版本,重复调用仅以第一次为准。
*/
export function setDebugLogger(callback : (log : string) => void) {
const ctx = UTSAndroid.getAppContext();
if (ctx != null) {
GTPlugin.setDebugLogger(ctx, new UserLoggerInterface(callback))
}
}
\ No newline at end of file
import { GetPushClientIdOptions, GetPushClientIdSuccess, GetPushClientIdFail, OnPushMessageCallback, OnPushMessageCallbackResult, OnPushMessageType, CreatePushMessageOptions, ChannelManager } from '../interface.uts'
import { gtInit, GTPushActionOptions, UserPushAction, setPushAction } from './gt-sdk/GTPush.uts'
import Context from 'android.content.Context';
import { PushMessage } from './push/PushMessage.uts';
import PackageManager from 'android.content.pm.PackageManager';
import ApplicationInfo from 'android.content.pm.ApplicationInfo';
import Activity from 'android.app.Activity';
import TextUtils from 'android.text.TextUtils';
import { PushState } from './push/PushState.uts';
import { PushManager } from './push/PushManager.uts';
import { StringUtil } from './push/utils/StringUtil.uts';
import SharedPreferences from 'android.content.SharedPreferences';
import Handler from 'android.os.Handler';
import { PushChannelManager } from './push/PushChannelManager.uts';
import Bundle from 'android.os.Bundle';
import Intent from 'android.content.Intent';
import Uri from 'android.net.Uri';
import { globalPushMessageCallbacks, sendEvent } from './push/PushManager.uts'
export { PushActionService } from './push/PushActionService.uts';
const SP_NAME = "clientid_unipush";
const SP_KEY_CLIENT_ID = "clientid";
let gtCallBack : UserPushAction | null = null;
let gtPushInitialize = false
/**
* 个推推送sdk初始化
*/
function initPush() {
const ctx = UTSAndroid.getAppContext();
if (ctx != null && !gtPushInitialize) {
gtPushInitialize = true;
gtInit(ctx);
setPushAction(getGTCallBack());
}
}
/**
* 获取客户端唯一的推送标识(注意:这是一个异步的方法)
*/
export function getPushClientId(options : GetPushClientIdOptions) {
initPush()
const ctx = UTSAndroid.getAppContext() as Context;
const sp = ctx.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE) as SharedPreferences;
const clientId = sp.getString(SP_KEY_CLIENT_ID, "")
if (TextUtils.isEmpty(clientId)) {
const handler = new Handler()
const changeListener = new (class implements SharedPreferences.OnSharedPreferenceChangeListener {
override onSharedPreferenceChanged(sharedPreferences : SharedPreferences, key : string) : void {
if (key != SP_KEY_CLIENT_ID) {
return
}
handler.removeCallbacksAndMessages(null)
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
const cid = sharedPreferences.getString(SP_KEY_CLIENT_ID, "")
const res : GetPushClientIdSuccess = { errMsg: "success", cid: cid!! }
options.success?.(res)
options.complete?.(res)
}
})
sp.registerOnSharedPreferenceChangeListener(changeListener)
const runnable = new (class implements Runnable {
override run() {
const clientId = sp.getString(SP_KEY_CLIENT_ID, "")
if (!TextUtils.isEmpty(clientId)) {
const res : GetPushClientIdSuccess = { errMsg: "success", cid: clientId!! }
options.success?.(res)
options.complete?.(res)
} else {
const res : GetPushClientIdFail = {
errSubject: "uni-push",
errCode: -1,
errMsg: "failed,check appkey or appid",
}
options.fail?.(res)
options.complete?.(res)
}
}
})
handler.postDelayed(runnable, 15000)
} else {
const res : GetPushClientIdSuccess = { errMsg: "success", cid: clientId!! }
options.success?.(res)
options.complete?.(res)
}
}
/**
* 增加监听推送消息事件(应用在线的时候没有通知栏消息,全部是透传。), 注意: 使用时,开发者需要注册写到第一个activity的周期内 , 即首页.
*/
export function onPushMessage(callback : OnPushMessageCallback | null) {
initPush()
if (callback == null) {
return;
}
if (globalPushMessageCallbacks.indexOf(callback) == -1) {
globalPushMessageCallbacks.push(callback)
}
processOfflineMessage()
// 处理没有注册监听时,已经接到的消息,此时从缓存里取
PushManager.getInstance().comsumeMessages("click", (msgs : PushMessage[]) => {
msgs.forEach((msg) => {
sendEvent("click", msg)
})
})
PushManager.getInstance().comsumeMessages("receive", (msgs : PushMessage[]) => {
msgs.forEach((msg) => {
sendEvent("receive", msg)
})
})
}
/**
* 移除推送消息监听事件(没有传入参数,则移除App级别的所有事件监听器。)
*/
export function offPushMessage(callback : OnPushMessageCallback | null) {
if (callback == null) {
const len = globalPushMessageCallbacks.length;
globalPushMessageCallbacks.splice(0, len)
return;
}
let index = globalPushMessageCallbacks.indexOf(callback)
if (index == -1) {
return;
}
globalPushMessageCallbacks.splice(index, 1)
}
export function getChannelManager() : ChannelManager {
return PushChannelManager.getInstance()
}
export function createPushMessage(options : CreatePushMessageOptions) : void {
const context = UTSAndroid.getAppContext() as Context
const appId = UTSAndroid.getAppId()
const pushMessage = new PushMessage(JSON.stringify(options), getApplicationName(), false)
const min = 0
if (pushMessage.mDelay == min.toLong()) {
PushManager.getInstance().addPushMessage(appId, pushMessage)
PushManager.getInstance().createNotification(context, pushMessage)
} else {
new Handler().postDelayed(new (class implements Runnable {
override run() {
PushManager.getInstance().addPushMessage(appId, pushMessage)
PushManager.getInstance().createNotification(context, pushMessage)
}
}), pushMessage.mDelay * 1000)
}
}
function getGTCallBack() : UserPushAction {
if (gtCallBack == null) {
const options = {
onReceiveClientId(cid : string) {
const context = UTSAndroid.getAppContext() as Context;
const sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
const editor = sp.edit();
editor.putString(SP_KEY_CLIENT_ID, cid);
editor.commit();
},
onNotificationMessageClicked(res : string) {
const pushMessage = new PushMessage(res, getApplicationName(), false)
if (!sendEvent("click", pushMessage)) {
PushManager.getInstance().addNeedExecClickMessage(pushMessage)
}
},
onReceiveMessageData(res : string) {
if (!TextUtils.isEmpty(res)) {
let isUniPush2 = false
const jsonObject = JSON.parseObject(res)
const unipushVersionStr = jsonObject?.getString("unipush_version")
if (!TextUtils.isEmpty(unipushVersionStr)) {
const unipushVersion = parseFloat(unipushVersionStr!!)
if (unipushVersion == 2.0) {
isUniPush2 = true;
}
}
if (isUniPush2) {
processForUniPush2(res);
} else {
processForUniPush(res);
}
}
},
} as GTPushActionOptions;
gtCallBack = new UserPushAction(options);
}
return gtCallBack!!;
}
/**
* 处理离线消息
*/
function processOfflineMessage() {
const activity = UTSAndroid.getUniActivity() as Activity
const intent = activity.getIntent()
// const testStr = "intent://io.dcloud.unipush/?#Intent;scheme=unipush;launchFlags=0x4000000;package=uni.UNI8CD4C4C;component=uni.UNI8CD4C4C/io.dcloud.uniapp.UniAppActivity;S.UP-OL-SU=true;S.unipush_version=2.0;S.payload={\"cccccforceNotification\":\"xxx\",\"path\":\"XXX\"};S.title=xxx;S.content=xxx;S.unipush_data={\"forceNotification\":\"xxx\",\"path\":\"XXX\"};end"
// const intent = Intent.parseUri(testStr , 0)
if (intent.hasExtra("UP-OL-SU")) {
let isUniPush2 = false;
const unipushVersionStr = intent.getStringExtra("unipush_version");
if (!TextUtils.isEmpty(unipushVersionStr)) {
const unipushVersion = parseFloat(unipushVersionStr!!)
if (unipushVersion == 2.0) {
isUniPush2 = true;
}
}
const params = {}
if (isUniPush2) {
try {
params["title"] = intent.getStringExtra("title")
params["content"] = intent.getStringExtra("content")
params["unipush_version"] = intent.getStringExtra("unipush_version")
const channelId = intent.getStringExtra("channelId");
const category = intent.getStringExtra("category");
if (!TextUtils.isEmpty(channelId)) {
params["channelId"] = channelId
}
if (!TextUtils.isEmpty(category)) {
params["category"] = category
}
let payload = intent.getStringExtra("payload");
const payloadJsonObject = JSON.parseObject(payload ?? "")
if (payloadJsonObject == null) {
if (payload != null) {
//如果后端传的不是json,而是纯字符串,就需要单独处理,去掉多余的引号,并且枚举一下类型.
//双引号套双引号,就说明是传的字符串.
if (payload.startsWith("\"")) {
payload = StringUtil.trimString(payload, '"');
params["payload"] = payload
} else {
const payloadInt = StringUtil.getInt(payload);
const payloadDouble = StringUtil.getDouble(payload);
if (payloadInt != null) {
params["payload"] = payloadInt
} else if (payloadDouble != null) {
params["payload"] = payloadDouble
} else if (payload == "true" || payload == "false") {
params["payload"] = payload.toBoolean()
} else {
params["payload"] = payload
}
}
}
} else {
params["payload"] = payloadJsonObject
}
const unipush_data = intent.getStringExtra("unipush_data");
const unipushDataJsonObject = JSON.parseObject(unipush_data ?? "");
if (unipushDataJsonObject != null) {
unipushDataJsonObject.toMap().forEach((value, key) => {
params[key] = value
})
}
intent.removeExtra("UP-OL-SU");
intent.removeExtra("title");
intent.removeExtra("content");
intent.removeExtra("payload");
intent.removeExtra("unipush_version");
intent.removeExtra("unipush_data");
intent.removeExtra("channelId");
intent.removeExtra("category");
const data = JSON.stringify(params)
const pushMessage = new PushMessage(data, getApplicationName(), true);
if (!sendEvent("click", pushMessage)) {
PushManager.getInstance().addNeedExecClickMessage(pushMessage)
}
} catch (e : Exception) {
e.printStackTrace();
}
} else {
try {
params["title"] = intent.getStringExtra("title")
params["content"] = intent.getStringExtra("content")
params["payload"] = intent.getStringExtra("payload")
const channelId = intent.getStringExtra("channelId");
const category = intent.getStringExtra("category");
if (!TextUtils.isEmpty(channelId)) {
params["channelId"] = channelId
}
if (!TextUtils.isEmpty(category)) {
params["category"] = category
}
intent.removeExtra("UP-OL-SU");
intent.removeExtra("title");
intent.removeExtra("content");
intent.removeExtra("payload");
intent.removeExtra("channelId");
intent.removeExtra("category");
const data = JSON.stringify(params)
const pushMessage = new PushMessage(data, getApplicationName(), true);
if (!sendEvent("click", pushMessage)) {
PushManager.getInstance().addNeedExecClickMessage(pushMessage)
}
} catch (e : Exception) {
e.printStackTrace();
}
}
}
}
function processForUniPush(data : string) : void {
const context = UTSAndroid.getAppContext() as Context
const pushMessage = new PushMessage(data, getApplicationName(), false)
const needPush = PushState.getAutoNotification()
if (needPush && pushMessage.getNeedCreateNotification()) {
PushManager.getInstance().createNotification(context, pushMessage)
} else if (!sendEvent("receive", pushMessage)) {
PushManager.getInstance().addNeedExecReceiveMessage(pushMessage);
}
PushManager.getInstance().addPushMessage(UTSAndroid.getAppId(), pushMessage);
}
function processForUniPush2(data : string) : void {
const context = UTSAndroid.getAppContext() as Context
const jsonObject = JSON.parseObject(data)
if (jsonObject != null) {
const forceNotification = jsonObject.getBoolean("force_notification")
const pushMessage = new PushMessage(data, getApplicationName(), true)
if (forceNotification != null && forceNotification) {
PushManager.getInstance().createNotification(context, pushMessage)
} else if (!sendEvent("receive", pushMessage)) {
PushManager.getInstance().addNeedExecReceiveMessage(pushMessage);
}
PushManager.getInstance().addPushMessage(UTSAndroid.getAppId(), pushMessage);
}
}
function getApplicationName() : string {
let packageManager : PackageManager | null = null
let applicationInfo : ApplicationInfo | null = null
const context = UTSAndroid.getAppContext() as Context;
try {
packageManager = context.getApplicationContext().getPackageManager()
applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0)
} catch (_ : Exception) {
}
if (applicationInfo == null) {
return ""
}
return packageManager?.getApplicationLabel(applicationInfo).toString() ?? ""
}
\ No newline at end of file
import Service from 'android.app.Service';
import Intent from 'android.content.Intent';
import IBinder from 'android.os.IBinder';
import { PushManager } from './PushManager.uts';
export class PushActionService extends Service {
constructor(){
super();
}
override onBind(intent : Intent) : IBinder | null {
return null
}
override onStartCommand(intent : Intent | null, flag : Int, startId : Int) : Int {
if (intent != null) {
PushManager.getInstance().processAction(this.getBaseContext(), intent)
}
return super.onStartCommand(intent, flag, startId)
}
}
\ No newline at end of file
import { ChannelManager, SetPushChannelOptions } from "../../interface.uts";
import Context from 'android.content.Context';
import Build from 'android.os.Build';
import NotificationManager from 'android.app.NotificationManager';
import NotificationChannelGroup from 'android.app.NotificationChannelGroup';
import NotificationChannel from 'android.app.NotificationChannel';
import TextUtils from 'android.text.TextUtils';
import ContentResolver from 'android.content.ContentResolver';
import Uri from 'android.net.Uri';
import RingtoneManager from 'android.media.RingtoneManager';
export class PushChannelManager implements ChannelManager {
static LOCAL_PUSH_CHANNEL_ID = "DcloudChannelID";
static LOCAL_PUSH_GROUP_ID = "DcloudGroupID";
private static INSTANCE : PushChannelManager | null = null
static getInstance() : PushChannelManager {
if (this.INSTANCE == null) {
this.INSTANCE = new PushChannelManager()
}
return this.INSTANCE!!
}
createDefaultChannel(context : Context) {
if (Build.VERSION.SDK_INT >= 26) {
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
const pChannelId = PushChannelManager.LOCAL_PUSH_CHANNEL_ID
const pChannelName = context.getResources().getString(R.string.dcloud_feature_aps_notification_channel)
if (notificationManager.getNotificationChannel(pChannelId) == null) {
notificationManager.createNotificationChannelGroup(new NotificationChannelGroup(PushChannelManager.LOCAL_PUSH_GROUP_ID, context.getResources().getString(R.string.dcloud_feature_aps_notification_group)))
const channel = new NotificationChannel(pChannelId, pChannelName, NotificationManager.IMPORTANCE_DEFAULT)
channel.enableLights(true)
channel.setShowBadge(true)
notificationManager.createNotificationChannel(channel)
}
}
}
/**
* 设置推送渠道
*/
setPushChannel(options : SetPushChannelOptions) : void {
if (Build.VERSION.SDK_INT >= 26) {
const context = UTSAndroid.getAppContext() as Context
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
if (notificationManager.getNotificationChannel(options.channelId) == null) {
const notificationChannel = new NotificationChannel(options.channelId, options.channelDesc, NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setShowBadge(true);
let sound = 0;
if (!TextUtils.isEmpty(options.soundName)) {
const packName = context.getApplicationInfo().packageName
sound = context.getResources().getIdentifier(options.soundName!!, "raw", packName)
}
let uriStr = "";
if (sound != 0) {
uriStr = ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.getPackageName() + "/raw/" + sound;
}
if (!TextUtils.isEmpty(uriStr)) {
notificationChannel.setSound(Uri.parse(uriStr), null);
} else {
const uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);//默认铃音
notificationChannel.setSound(uri, null);
}
if (options.importance != null) {
notificationChannel.setImportance(options.importance!!.toInt());
}
if (options.lockscreenVisibility != null) {
notificationChannel.setLockscreenVisibility(options.lockscreenVisibility!!.toInt());
}
notificationChannel.enableLights(options.enableLights ?? false);
notificationChannel.enableVibration(options.enableVibration ?? false);
notificationManager.createNotificationChannel(notificationChannel);
}
}
}
/**
* 获取当前应用注册的所有的通知渠道。
*/
getAllChannels() : string[] {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
const context = UTSAndroid.getAppContext() as Context
const nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
const channels : string[] = []
const list = nm.getNotificationChannels()
for (let i:Int = 0; i < list.size; i++) {
channels.push(list.get(i).toString())
}
return channels
}else{
return [] as string[]
}
}
}
\ No newline at end of file
import Context from 'android.content.Context';
import Intent from 'android.content.Intent';
import { PushChannelManager } from './PushChannelManager.uts';
import { PushMessage } from './PushMessage.uts';
import NotificationManager from 'android.app.NotificationManager';
import ComponentName from 'android.content.ComponentName';
import PendingIntent from 'android.app.PendingIntent';
import Build from 'android.os.Build';
import TextUtils from 'android.text.TextUtils';
import Notification from 'android.app.Notification';
import Bitmap from 'android.graphics.Bitmap';
import BitmapFactory from 'android.graphics.BitmapFactory';
import File from 'java.io.File';
import { OnPushMessageCallback, OnPushMessageType, OnPushMessageCallbackResult } from '../../interface.uts'
export const globalPushMessageCallbacks : OnPushMessageCallback[] = []
export function sendEvent(type : OnPushMessageType, pushMessage : PushMessage) : boolean {
const data = pushMessage.getJsonObject()
const result : OnPushMessageCallbackResult = {
type: type,
data: data
}
if (globalPushMessageCallbacks.length == 0) {
return false
} else {
globalPushMessageCallbacks.forEach((cb : OnPushMessageCallback) => {
cb(result)
})
return true
}
}
export class PushManager {
private static INSTANCE : PushManager | null = null
private ACTION_TYPE_CREATE = "ACTION_TYPE_CREATE"
private ACTION_TYPE_REMOVE = "ACTION_TYPE_REMOVE"
private ACTION_TYPE_CLEAR = "ACTION_TYPE_CLEAR"
private ACTION_TYPE_CLICK = "ACTION_TYPE_CLICK"
private mAppMessages : Map<string, Array<PushMessage>> = new Map()
private mNeedExecClickMessages : PushMessage[] = []
private mNeedExecReceiveMessages : PushMessage[] = []
static getInstance() : PushManager {
if (this.INSTANCE == null) {
this.INSTANCE = new PushManager()
}
return this.INSTANCE!!
}
createNotification(context : Context, message : PushMessage) {
PushChannelManager.getInstance().createDefaultChannel(context)
const intent = new Intent(this.ACTION_TYPE_CREATE)
intent.putExtras(message.toBundle())
this.processAction(context, intent)
}
addPushMessage(pAppid : string, pMsg : PushMessage) {
let _arr = this.mAppMessages.get(pAppid);
if (_arr == null) {
_arr = new Array<PushMessage>();
this.mAppMessages.set(pAppid, _arr);
}
_arr.push(pMsg);
}
addNeedExecClickMessage(pushMessage : PushMessage) {
if (this.mNeedExecClickMessages.length > 0) {
this.mNeedExecClickMessages = []
}
this.mNeedExecClickMessages.push(pushMessage)
}
addNeedExecReceiveMessage(pushMessage : PushMessage) {
this.mNeedExecReceiveMessages.push(pushMessage)
}
removePushMessage(pAppid : String, pPushMsg : PushMessage) {
const _arr = this.mAppMessages.get(pAppid);
if (_arr != null && _arr.indexOf(pPushMsg) > 0) {
_arr.splice(_arr.indexOf(pPushMsg), 1);
}
}
/**
* 消费缓存的消息
*/
comsumeMessages(type : string, cb : (msgs : PushMessage[]) => void) {
if (type == "click") {
cb(this.mNeedExecClickMessages)
this.mNeedExecClickMessages.splice(0)
} else if (type == "receive") {
cb(this.mNeedExecReceiveMessages)
this.mNeedExecReceiveMessages.splice(0)
}
}
processAction(context : Context, intent : Intent) {
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
const action = intent.getAction()
switch (action) {
case this.ACTION_TYPE_CREATE:
{
const title = intent.getStringExtra("title");
const message = intent.getStringExtra("content");
const nId = intent.getIntExtra("nId", 0);
const when = intent.getLongExtra("when", 0);
const appid = intent.getStringExtra("appid");
const icon = intent.getStringExtra("icon");
const sound = intent.getStringExtra("sound");
const category = intent.getStringExtra("category");
let channelId = intent.getStringExtra("channelId");
const i = new Intent(this.ACTION_TYPE_CLICK);
i.setComponent(new ComponentName(context.getPackageName(), "uts.sdk.modules.DCloudUniPush.PushActionService"));
i.putExtras(intent.getExtras()!!);
let flags = PendingIntent.FLAG_ONE_SHOT;
if (Build.VERSION.SDK_INT >= 23) {
flags = PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE;
}
const contentIntent = PendingIntent.getService(context, nId, i, flags);
let builder : Notification.Builder | null = null;
if (Build.VERSION.SDK_INT >= 26) {
if (TextUtils.isEmpty(channelId)) {
channelId = PushChannelManager.LOCAL_PUSH_CHANNEL_ID;
}
builder = new Notification.Builder(context, channelId);
} else {
builder = new Notification.Builder(context);
}
let bitmap : Bitmap | null = null;
try {
if (!TextUtils.isEmpty(icon) && this.fileIsExist(icon!!)) {
bitmap = BitmapFactory.decodeFile(icon!!);
}
} catch (e : Exception) {
e.printStackTrace();
}
if (bitmap != null) {
builder.setLargeIcon(bitmap);
}
const id_small = context.getResources().getIdentifier("push_small", "drawable", context.getPackageName())
if (id_small <= 0) {
builder.setSmallIcon(context.getApplicationInfo().icon); //设置图标
} else {
builder.setSmallIcon(id_small); //设置图标
}
const id = context.getResources().getIdentifier("push", "drawable", context.getPackageName())
if (bitmap == null) {
let largeBitmap : Bitmap | null = null;
if (id <= 0) {
largeBitmap = BitmapFactory.decodeResource(context.getResources(), context.getApplicationInfo().icon);
} else {
largeBitmap = BitmapFactory.decodeResource(context.getResources(), id);
}
if (null != largeBitmap) {
builder.setLargeIcon(largeBitmap);
}
}
builder.setContentTitle(title); //设置标题
builder.setContentText(message); //消息内容
if (Build.VERSION.SDK_INT >= 24) {
builder.setShowWhen(true);
}
builder.setWhen(when); //发送时间
// 添加声音提示
if ("system" == sound) {
builder.setDefaults(Notification.DEFAULT_SOUND); //设置默认的提示音,振动方式,灯光
}
builder.setAutoCancel(true);//打开程序后图标消失
builder.setContentIntent(contentIntent);
builder.setCategory(category);
const notification = builder.build();
try {
notificationManager.notify(nId, notification);
} catch (e : Exception) {
e.printStackTrace();
}
}
break;
case this.ACTION_TYPE_REMOVE:
{
const _id = intent.getIntExtra("id", 0);
if (_id != null) {
notificationManager.cancel(_id);
}
}
break;
case this.ACTION_TYPE_CLEAR:
{
notificationManager.cancelAll();
const _appid = intent.getStringExtra("_appId");
if (_appid != null) {
const appMsg = PushManager.getInstance().mAppMessages;
appMsg.delete(_appid);
}
}
break;
case this.ACTION_TYPE_CLICK:
{
this.clickHandle(intent, notificationManager);
const packagename = context.getPackageName();// 启动类所在包名
const pm = context.getPackageManager();
const _intent = pm.getLaunchIntentForPackage(packagename);
const appid = intent.getStringExtra("appid");
_intent?.putExtra("appid", appid);
const isStartWeb = intent?.getBooleanExtra("__start_first_web__", false) ?? false;
if (isStartWeb) {
_intent?.putExtra("__start_first_web__", isStartWeb);
_intent?.putExtra("__first_web_url__", intent?.getStringExtra("__first_web_url__"));
}
_intent?.putExtra("__start_from__", 3);
_intent?.putExtra("__payload__", intent?.getStringExtra("payload"));
_intent?.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(_intent);
}
break;
}
}
clickHandle(intent : Intent, _notificationManager : NotificationManager) {
const _bundle = intent.getExtras()!!;
const appid = _bundle.getString("appid");
const uuid = _bundle.getString("uuid");
if (_notificationManager != null) {//作为插件时,手助负责创建通知栏消息
const _id = intent.getIntExtra("id", 0);
_notificationManager.cancel(_id);
}
let _pushMessage : PushMessage | null = null
if (appid != null && uuid != null) {
_pushMessage = this.findPushMessage(appid!!, uuid!!);
}
if (_pushMessage != null) {
let isStartWeb = false;
if (!TextUtils.isEmpty(_pushMessage.mPayload)) {
try {
const payLoadJson = JSON.parseObject(_pushMessage.mPayload ?? "")
const url = payLoadJson?.getString("__adurl")
if (!TextUtils.isEmpty(url)) {
intent.putExtra("__start_first_web__", true);
intent.putExtra("__first_web_url__", url);
isStartWeb = true;
}
} catch (e : Exception) {
e.printStackTrace();
}
}
if (!isStartWeb && !sendEvent("click", _pushMessage)) {
this.addNeedExecClickMessage(_pushMessage);
}
// 点击后的消息,需要移除消息记录,避免getAllMessage时不正确
if (appid != null) {
this.removePushMessage(appid, _pushMessage);
}
} else {
_pushMessage = new PushMessage(_bundle);
if (!TextUtils.isEmpty(_pushMessage.mPayload)) {
try {
const payLoadJson = JSON.parseObject(_pushMessage.mPayload!!)
const url = payLoadJson?.getString("__adurl")
if (!TextUtils.isEmpty(url)) {
intent.putExtra("__start_first_web__", true);
intent.putExtra("__first_web_url__", url);
}
} catch (e : Exception) {
e.printStackTrace();
}
}
this.addNeedExecClickMessage(_pushMessage);
}
_bundle.clear();
}
findPushMessage(pAppid : String, pUuid : String) : PushMessage | null {
let _ret : PushMessage | null = null;
const _arr = this.mAppMessages.get(pAppid);
if (_arr == null) {//若没有通过appid获取到消息集合,则通过uuid遍历所有消息
this.mAppMessages.forEach((value : PushMessage[], key : string) => {
if (value != null) {
value.forEach((value : PushMessage) => {
if (pUuid == value.getMessageUUID()) {
_ret = value
}
})
}
})
} else if (_arr != null) {
_arr.forEach((value : PushMessage) => {
if (pUuid == value.getMessageUUID()) {
_ret = value
}
})
}
return _ret;
}
fileIsExist(path : string) : boolean {
const realPath = UTSAndroid.convert2AbsFullPath(path)
const file = new File(realPath)
return file.exists()
}
}
\ No newline at end of file
import TextUtils from 'android.text.TextUtils'
import Bundle from 'android.os.Bundle';
export class PushMessage {
private mTitle : string | null = null
private contentJson : string | null = null
private mContent : string | null = null
mPayloadJSON : UTSJSONObject | null = null
mPayload : string | null = null
private mWhen : Long = 0
mDelay : Long = 0
private mPath : string | null = null
private mForceNotification : string | null = null
private channelId = ""
private category = ""
private mMessageAppid : string | null = null
private mIconPath : string | null = null
private mUUID : string | null = null
private nID : number = 0
private isCover = false
private sound = "system"
private static mNotificationId = 1
private needCreateNotification = true
private pushVersion : Float = 1.0.toFloat()
private extJSON : UTSJSONObject | null = null
constructor(data : string, defaultTitle : string, isUniPush2 : boolean) {
if (!isUniPush2) {
this.contentJson = data
this.parseJson(data, UTSAndroid.getAppId(), defaultTitle)
} else {
this.extJSON = JSON.parseObject(data)
this.mMessageAppid = UTSAndroid.getAppId()
this.pushVersion = 2.0.toFloat()
if (this.extJSON != null) {
this.channelId = this.extJSON!!.getString("channelId") ?? ""
this.category = this.extJSON!!.getString("category") ?? ""
}
}
this.setMessageUUID()
this.setNotificationID()
}
$constructor(b : Bundle) {
this.mTitle = b.getString("title");
this.mContent = b.getString("content");
this.nID = b.getInt("nId");
this.mWhen = b.getLong("when");
this.sound = b.getString("sound") ?? "system";
this.mMessageAppid = b.getString("appid");
this.mUUID = b.getString("uuid");
this.mPayload = b.getString("payload");
this.mIconPath = b.getString("icon");
this.channelId = b.getString("channelId", "");
this.category = b.getString("category", "");
}
getNeedCreateNotification() : boolean {
return this.needCreateNotification;//payload为空串时需要创建
}
getMessageUUID() : string | null {
return this.mUUID
}
getJsonObject() : UTSJSONObject {
if (this.extJSON != null) {
if (this.pushVersion == (2.0.toFloat())) {
try {
this.extJSON!!["__UUID__"] = this.mUUID
this.extJSON!!["appid"] = this.mMessageAppid
} catch (e : Exception) {
e.printStackTrace()
return {};
}
}
return this.extJSON!!
} else {
const result = {} as UTSJSONObject;
result["__UUID__"] = this.mUUID
result["title"] = this.mTitle
result["appid"] = this.mMessageAppid
result["content"] = this.mContent
if (this.mPayloadJSON != null) {
result["payload"] = this.cleanNullValue(this.mPayloadJSON!!)
} else {
let payLoadObj : UTSJSONObject | null = null
if (this.mPayload != null) {
payLoadObj = JSON.parseObject(this.mPayload!!)
}
if (payLoadObj != null) {
result["payload"] = this.cleanNullValue(payLoadObj)
} else {
result["payload"] = this.mPayload
}
}
if (!TextUtils.isEmpty(this.mPath)) {
result["path"] = this.mPath
}
if (!TextUtils.isEmpty(this.mForceNotification)) {
result["force_notification"] = this.mForceNotification
}
if (!TextUtils.isEmpty(this.channelId)) {
result["channelId"] = this.channelId
}
if (!TextUtils.isEmpty(this.category)) {
result["category"] = this.category
}
return result
}
}
cleanNullValue(json : UTSJSONObject) : UTSJSONObject {
const result = {}
json.toMap().forEach((value, key) => {
if (value != null) {
result[key] = value
}
})
return result
}
toBundle() : Bundle {
const bundle = new Bundle()
if (this.extJSON != null && this.pushVersion == (2.0.toFloat())) {
bundle.putInt("nId", this.nID.toInt());
bundle.putLong("when", this.mWhen);
bundle.putString("sound", this.sound);
bundle.putString("appid", this.mMessageAppid);
bundle.putString("uuid", this.mUUID);
bundle.putString("icon", this.mIconPath);
const map = this.extJSON!!.toMap()
map.forEach((value, key) => {
if (value != null) {
if (typeof value == 'string') {
bundle.putString(key, value as string);
} else if (value instanceof Integer) {
bundle.putInt(key, value as Int);
} else if (value instanceof Double) {
bundle.putDouble(key, value);
} else if (typeof value == 'boolean') {
bundle.putBoolean(key, value as boolean);
} else if (value instanceof UTSJSONObject) {
bundle.putString(key, (value as UTSJSONObject).toJSONString());
}
}
})
return bundle
}
bundle.putString("title", this.mTitle);
bundle.putString("content", this.mContent);
bundle.putInt("nId", this.nID.toInt());
bundle.putLong("when", this.mWhen);
bundle.putString("sound", this.sound);
bundle.putString("appid", this.mMessageAppid);
bundle.putString("uuid", this.mUUID);
if (this.mPayloadJSON != null) {
bundle.putString("payload", this.mPayloadJSON!!.toJSONString());
} else {
bundle.putString("payload", this.mPayload);
}
bundle.putString("icon", this.mIconPath);
bundle.putString("channelId", this.channelId);
bundle.putString("category", this.category);
return bundle
}
private setMessageUUID() : void {
this.mUUID = "androidPushMsg" + this.hashCode()
}
private setNotificationID() : void {
if (!this.isCover) {
PushMessage.mNotificationId++
}
this.nID = PushMessage.mNotificationId
}
/**
* 解析消息的数据
* @param defaultAppid 通过appid 查询到icon资源 , 1.0强需求, 2.0 不需求
*/
private parseJson(data : string, defaultAppid : string, defaultTitle : string) : void {
const json = JSON.parseObject(data)
if (json != null) {
let t_appid = json.getString("appid")
const content = json.getString("content")
if (content != null) {
this.mContent = content
} else {
const message = json.getString("message")
if (message != null) {
this.mContent = message
} else {
this.needCreateNotification = true
this.mContent = data
}
}
if (this.hasOwnProperty(json, "payload")) {
const payloadJson = json.getJSON("payload")
if (payloadJson != null) {
this.mPayloadJSON = payloadJson
} else {
this.mPayload = json.getString("payload")
}
} else {
if (this.hasOwnProperty(json, "Payload")) {
const payloadJson = json.getJSON("Payload")
if (payloadJson != null) {
this.mPayloadJSON = payloadJson
} else {
this.mPayload = json.getString("Payload")
}
} else {
this.needCreateNotification = false
this.mPayload = data
}
}
if (this.hasOwnProperty(json, "title")) {
this.mTitle = json.getString("title")
} else {
this.needCreateNotification = false
this.mTitle = defaultTitle
}
this.isCover = json.getBoolean("cover") ?? false
if ("none" == json.getString("sound")) {
this.sound = "none"
}
this.mWhen = (json.getNumber("when") ?? 0).toLong()
this.mDelay = (json.getNumber("delay") ?? 0).toLong()
this.mPath = json.getString("path")
this.mForceNotification = json.getString("force_notification")
this.channelId = json.getString("channelId") ?? ""
this.category = json.getString("category") ?? ""
if (TextUtils.isEmpty(t_appid)) {
t_appid = defaultAppid
}
this.mMessageAppid = t_appid
const iconPath = json.getString("icon") ?? ""
this.mIconPath = UTSAndroid.convert2AbsFullPath(iconPath)
} else {
this.needCreateNotification = false
this.mContent = data
this.mPayload = data
this.mTitle = defaultTitle
}
}
private hasOwnProperty(jsonObject : UTSJSONObject, key : string) : boolean {
return jsonObject.getAny(key) != null
}
}
\ No newline at end of file
import Context from 'android.content.Context';
import PackageManager from 'android.content.pm.PackageManager';
import Bundle from 'android.os.Bundle';
import TextUtils from 'android.text.TextUtils';
export class PushState {
private static sMetaDatas : Bundle | null = null
static getAutoNotification() : boolean {
const context = UTSAndroid.getAppContext() as Context
const sp = context.getSharedPreferences("push_db_name", Context.MODE_PRIVATE)
const autoNotification = this.getMetaValue(context, "dcloud_unipush_auto_notification")
let needPush = true
if (autoNotification != null) {
if (!autoNotification.equals("ture", true)) {
needPush = false;
}
}
needPush = sp.getBoolean("auto_notification", needPush);
return needPush
}
private static getMetaValue(context : Context, metaKey : string) : string | null {
if (this.sMetaDatas == null) {
try {
this.sMetaDatas = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA).metaData;
} catch (e : Exception) {
e.printStackTrace();
return null;
}
}
if (this.sMetaDatas != null) {
const value = this.sMetaDatas!!.get(metaKey)
if (value != null && !TextUtils.isEmpty(value as string)) {
return value as string;
}
}
return null;
}
}
\ No newline at end of file
export class StringUtil {
static trimString(pSrc : string, removed : string) : string {
const pTrimChar = removed.charAt(0)
let _ret = pSrc;
if (_ret != null && _ret != "") {
const _startPosi = _ret.charAt(0) == pTrimChar ? 1 : 0;
const _count = _ret.length;
const _endPosi = _ret.charAt(_count - 1) == pTrimChar ? _count - 1 : _count;
_ret = _ret.substring(_startPosi, _endPosi);
}
return _ret;
}
static getInt(content : string) : number | null {
try {
return content.toInt();
} catch (e : Exception) {
return null;
}
}
static getDouble(content : string) : number | null {
try {
return content.toDouble()
} catch (e : Exception) {
return null;
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/getui_notification,
@drawable/push,
@drawable/push_small,
/>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="dcloud_feature_aps_notification_channel">消息推送</string>
<string name="dcloud_feature_aps_notification_group">推送消息</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="dcloud_feature_aps_notification_channel" >unipush</string>
<string name="dcloud_feature_aps_notification_group" >message push</string>
</resources>
\ No newline at end of file
export interface Uni {
/**
* getPushClientId()
* @description
* 获取客户端唯一的推送标识
* @param {GetPushClientIdOptions}
* @return {void}
* @tutorial http://uniapp.dcloud.io/api/plugins/push.html#getpushclientid
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
* @example
```typescript
uni.getPushClientId({
complete: (res: any) => {
console.log("getPushClientId complete => " + JSON.stringify(res));
}
});
```
*/
getPushClientId(options : GetPushClientIdOptions) : void;
/**
* onPushMessage()
* @description
* 启动监听推送消息事件
* @param {OnPushMessageCallback}
* @return {void}
* @tutorial http://uniapp.dcloud.io/api/plugins/push.html#onpushmessage
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
* @example
```typescript
uni.onPushMessage((res : OnPushMessageCallbackResult) => {
console.log("onPushMessage => " + JSON.stringify(res))
});
```
*/
onPushMessage(callback : OnPushMessageCallback) : void;
/**
* offPushMessage()
* @description
* 关闭推送消息监听事件
* @param {OnPushMessageCallback}
* @return {void}
* @tutorial http://uniapp.dcloud.io/api/plugins/push.html#offpushmessage
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
* @example
```typescript
const cb = (res : OnPushMessageCallbackResult) => {
console.log("onPushMessage => " + JSON.stringify(res))
}
uni.offPushMessage(cb);
```
*/
offPushMessage(callback : OnPushMessageCallback) : void;
/**
* getChannelManager()
* @description
* 获取通知渠道管理器,Android 8系统以上才可以设置通知渠道,Android 8系统以下返回null。
* @param {void}
* @return {ChannelManager}
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "3.97",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
* @example
```typescript
const channelManager = uni.getChannelManager();
channelManager.setPushChannel({
channelId: "test1",
channelDesc: "test1 desc",
soundName: "pushsound"
})
const channels = channelManager.getAllChannels() as string[]
console.log("channels : " + channels);
```
*/
getChannelManager() : ChannelManager;
/**
* createPushMessage()
* @description
* 创建本地通知栏消息
* @param {CreatePushMessageOptions}
* @return {void}
* @tutorial http://uniapp.dcloud.io/api/plugins/push.html#createpushmessage
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
* @example
```typescript
uni.createPushMessage({
title:"hello",
content: "content"
});
```
*/
createPushMessage(options : CreatePushMessageOptions) : void;
}
export type GetPushClientId = (options : GetPushClientIdOptions) => void;
export type GetPushClientIdSuccess = {
/**
* 个推客户端推送id,对应uni-id-device表的push_clientid
*/
cid : string,
/**
* 错误描述
*/
errMsg : string
};
export type GetPushClientIdSuccessCallback = (result : GetPushClientIdSuccess) => void;
export type GetPushClientIdFail = UniError;
export type GetPushClientIdFailCallback = (result : GetPushClientIdFail) => void;
export type GetPushClientIdComplete = any;
export type GetPushClientIdCompleteCallback = (result : GetPushClientIdComplete) => void;
export type GetPushClientIdOptions = {
/**
* 接口调用成功的回调函数
* @defaultValue null
*/
success : GetPushClientIdSuccessCallback | null,
/**
* 接口调用失败的回调函数
* @defaultValue null
*/
fail : GetPushClientIdFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
* @defaultValue null
*/
complete : GetPushClientIdCompleteCallback | null
};
/**
* 事件类型
* - click 从系统推送服务点击消息启动应用事件
* - receive 应用从推送服务器接收到推送消息事件
*/
export type OnPushMessageType = "click" | "receive";
export type OnPushMessageCallbackResult = {
/**
* 事件类型
* @type{OnPushMessageType}
*/
type : OnPushMessageType,
/**
* 消息内容
*/
data : UTSJSONObject
};
export type OnPushMessageCallback = (result : OnPushMessageCallbackResult) => void;
export type OnPushMessage = (callback : OnPushMessageCallback) => void;
export type OffPushMessage = (callback : OnPushMessageCallback) => void;
export type GetChannelManager = () => ChannelManager;
export type SetPushChannelOptions = {
/**
* 添加的声音文件,注意raw目录下必须要有 ,不传此字段将使用默认铃音。
* @defaultValue null
*/
soundName? : string | null,
/**
* 通知渠道id
*/
channelId : string,
/**
* 通知渠道描述
*/
channelDesc : string,
/**
* 呼吸灯闪烁
* @defaultValue false
*/
enableLights? : boolean | null,
/**
* 震动
* @defaultValue false
*/
enableVibration? : boolean | null,
/**
* 通知的重要性级别,可选范围IMPORTANCE_LOW:2、IMPORTANCE_DEFAULT:3、IMPORTANCE_HIGH:4 。
* @defaultValue 3
*/
importance? : number | null,
/**
* 锁屏可见性,可选范围VISIBILITY_PRIVATE:0、VISIBILITY_PUBLIC:1、VISIBILITY_SECRET:-1、VISIBILITY_NO_OVERRIDE:-1000。
* @defaultValue -1000
*/
lockscreenVisibility? : number | null
}
export interface ChannelManager {
/**
* 设置推送渠道
*
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
setPushChannel(options : SetPushChannelOptions) : void;
/**
* 获取当前应用注册的所有的通知渠道。
*
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
getAllChannels() : Array<string>;
}
export type CreatePushMessage = (options : CreatePushMessageOptions) => void;
export type CreatePushMessageSuccess = {};
export type CreatePushMessageSuccessCallback = (result : CreatePushMessageSuccess) => void;
export type CreatePushMessageFail = UniError;
export type CreatePushMessageFailCallback = (result : CreatePushMessageFail) => void;
export type CreatePushMessageComplete = any;
export type CreatePushMessageCompleteCallback = (result : CreatePushMessageComplete) => void;
export type CreatePushMessageOptions = {
/**
* 是否覆盖上一次提示的消息
* @type boolean
* @defaultValue false
*/
cover? : boolean | null,
/**
* 提示消息延迟显示的时间,单位为s
* @defaultValue 0
*/
delay? : number | null,
/**
* 推送消息的图标
* @defaultValue null
*/
icon? : string | null,
/**
* 推送消息的提示音
* - system: 使用系统通知提示音(默认值)
* - none: 不使用提示音
* @type 'system' | 'none'
* @defaultValue "system"
*/
sound? : string | null,
/**
* 推送消息的标题
* @defaultValue ""
*/
title? : string | null,
/**
* 消息显示的内容,在系统通知中心中显示的文本内容
*/
content : string,
/**
* 消息承载的数据,可根据业务逻辑自定义数据格式
* @defaultValue null
*/
payload? : any | null,
/**
* 消息上显示的提示时间
* @defaultValue 当前时间
*/
when? : number | null,
/**
* 渠道id
* @defaultValue "DcloudChannelID"
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
channelId? : string | null,
/**
* 通知类别
* @defaultValue null
* @uniPlatform {
* "app": {
* "android": {
* "osVer": "4.4",
* "uniVer": "√",
* "unixVer": "3.97"
* },
* "ios": {
* "osVer": "9.0",
* "uniVer": "x",
* "unixVer": "x"
* }
* }
* }
*/
category? : string | null,
/**
* 接口调用成功的回调函数
* @defaultValue null
*/
success : CreatePushMessageSuccessCallback | null,
/**
* 接口调用失败的回调函数
* @defaultValue null
*/
fail : CreatePushMessageFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
* @defaultValue null
*/
complete : CreatePushMessageCompleteCallback | null
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册