提交 d1a80a04 authored 作者: 史晓晨's avatar 史晓晨

init

上级
{
"configVersion": 2,
"packages": [
{
"name": "async",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/async-2.11.0",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "boolean_selector",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.1",
"packageUri": "lib/",
"languageVersion": "2.17"
},
{
"name": "characters",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/characters-1.3.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "clock",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/clock-1.1.1",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "collection",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/collection-1.18.0",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "fake_async",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/fake_async-1.3.1",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "flutter",
"rootUri": "file:///Users/shixiaochen/work/flutter/packages/flutter",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "flutter_lints",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/flutter_lints-2.0.3",
"packageUri": "lib/",
"languageVersion": "2.19"
},
{
"name": "flutter_test",
"rootUri": "file:///Users/shixiaochen/work/flutter/packages/flutter_test",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "leak_tracker",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker-10.0.0",
"packageUri": "lib/",
"languageVersion": "3.1"
},
{
"name": "leak_tracker_flutter_testing",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_flutter_testing-2.0.1",
"packageUri": "lib/",
"languageVersion": "3.1"
},
{
"name": "leak_tracker_testing",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_testing-2.0.1",
"packageUri": "lib/",
"languageVersion": "3.1"
},
{
"name": "lints",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/lints-2.1.1",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "matcher",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.16+1",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "material_color_utilities",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/material_color_utilities-0.8.0",
"packageUri": "lib/",
"languageVersion": "2.17"
},
{
"name": "meta",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/meta-1.11.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "path",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/path-1.9.0",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "plugin_platform_interface",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/plugin_platform_interface-2.1.8",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "sky_engine",
"rootUri": "file:///Users/shixiaochen/work/flutter/bin/cache/pkg/sky_engine",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "source_span",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/source_span-1.10.0",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "stack_trace",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/stack_trace-1.11.1",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "stream_channel",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/stream_channel-2.1.2",
"packageUri": "lib/",
"languageVersion": "2.19"
},
{
"name": "string_scanner",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/string_scanner-1.2.0",
"packageUri": "lib/",
"languageVersion": "2.18"
},
{
"name": "term_glyph",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/term_glyph-1.2.1",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "test_api",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/test_api-0.6.1",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "vector_math",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/vector_math-2.1.4",
"packageUri": "lib/",
"languageVersion": "2.14"
},
{
"name": "vm_service",
"rootUri": "file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/vm_service-13.0.0",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "aliyun_push",
"rootUri": "../",
"packageUri": "lib/",
"languageVersion": "2.18"
}
],
"generated": "2025-09-09T05:26:01.341541Z",
"generator": "pub",
"generatorVersion": "3.3.4"
}
async
2.18
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/async-2.11.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/async-2.11.0/lib/
boolean_selector
2.17
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.1/lib/
characters
2.12
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/characters-1.3.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/characters-1.3.0/lib/
clock
2.12
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/clock-1.1.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/clock-1.1.1/lib/
collection
2.18
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/collection-1.18.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/collection-1.18.0/lib/
fake_async
2.12
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/fake_async-1.3.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/fake_async-1.3.1/lib/
flutter_lints
2.19
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/flutter_lints-2.0.3/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/flutter_lints-2.0.3/lib/
leak_tracker
3.1
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker-10.0.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker-10.0.0/lib/
leak_tracker_flutter_testing
3.1
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_flutter_testing-2.0.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_flutter_testing-2.0.1/lib/
leak_tracker_testing
3.1
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_testing-2.0.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/leak_tracker_testing-2.0.1/lib/
lints
3.0
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/lints-2.1.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/lints-2.1.1/lib/
matcher
3.0
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.16+1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.16+1/lib/
material_color_utilities
2.17
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/material_color_utilities-0.8.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/material_color_utilities-0.8.0/lib/
meta
2.12
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/meta-1.11.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/meta-1.11.0/lib/
path
3.0
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/path-1.9.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/path-1.9.0/lib/
plugin_platform_interface
3.0
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/plugin_platform_interface-2.1.8/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/plugin_platform_interface-2.1.8/lib/
source_span
2.18
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/source_span-1.10.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/source_span-1.10.0/lib/
stack_trace
2.18
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/stack_trace-1.11.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/stack_trace-1.11.1/lib/
stream_channel
2.19
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/stream_channel-2.1.2/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/stream_channel-2.1.2/lib/
string_scanner
2.18
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/string_scanner-1.2.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/string_scanner-1.2.0/lib/
term_glyph
2.12
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/term_glyph-1.2.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/term_glyph-1.2.1/lib/
test_api
3.0
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/test_api-0.6.1/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/test_api-0.6.1/lib/
vector_math
2.14
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/vector_math-2.1.4/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/vector_math-2.1.4/lib/
vm_service
3.0
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/vm_service-13.0.0/
file:///Users/shixiaochen/.pub-cache/hosted/pub.flutter-io.cn/vm_service-13.0.0/lib/
sky_engine
3.2
file:///Users/shixiaochen/work/flutter/bin/cache/pkg/sky_engine/
file:///Users/shixiaochen/work/flutter/bin/cache/pkg/sky_engine/lib/
flutter
3.2
file:///Users/shixiaochen/work/flutter/packages/flutter/
file:///Users/shixiaochen/work/flutter/packages/flutter/lib/
flutter_test
3.2
file:///Users/shixiaochen/work/flutter/packages/flutter_test/
file:///Users/shixiaochen/work/flutter/packages/flutter_test/lib/
aliyun_push
2.18
file:///Users/shixiaochen/work/project/aliyun_push_clx/
file:///Users/shixiaochen/work/project/aliyun_push_clx/lib/
2
3.19.6
\ No newline at end of file
## 0.0.1
* 集成Android推送 3.8.2版本,iOS推送1.9.9.7版本
## 0.0.2
* 更新LICENSE
## 0.0.3
* 内部代码优化
## 0.0.4
* README优化
* 代码优化
* 增加控制插件日志是否开启的API
## 0.0.5
* 修复Android创建Channel时desc字段key值不一致问题
## 0.0.6
* android代码增加保护机制
## 0.0.7
* ios初始化时增加网络判断
## 0.0.8
* Android升级到3.8.5版本
## 0.0.9
* 优化代码
## 0.1.0
* Android升级到3.8.6版本
## 0.1.1
* 回调参数类型转换错误修复
* Android 小米通道升级至3.8.6.1版本
## 0.1.7
* 修复因缺少namespace导致8.0以上agp构建失败问题
* 修改插件依赖配置,去除构建过程中因apply方式依赖插件输出的警告
* 去除初始化过程中调用turnOnPushChannel()导致控制台输出获取不到deviceId的问题
* 去除example中dropdown_button2依赖,改为通过弹出的方式设置logLevel
## 0.1.8
* 修复iOS可能出现的崩溃问题
* 修复iOS demo运行失败问题
## 1.0.0-beta.1
* 升级iOS端SDK版本
* 更新部分api
## 1.0.0
* 修复onNotification回调,Android端通知缺少title和summary字段的问题
\ No newline at end of file
MIT License
Copyright (c) 2023 Alibaba Cloud
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Aliyun Push Flutter Plugin
## 1. 项目简介
本库(`aliyun_push`)是一个 Flutter 推送通知插件,旨在简化 Android 和 iOS 平台集成阿里云推送服务的过程。通过封装原生阿里云推送 SDK (Android: `alicloud-android-push`, iOS: `AlicloudPush`),开发者可以更便捷地在 Flutter 应用中实现稳定、高效的推送通知功能,而无需深入了解原生平台的复杂配置。本库致力于提供一致的 dart API,降低跨平台开发的难度,提升开发效率。
## 2. 特性
- 🚀 **跨平台支持**:一套代码同时支持 Android 和 iOS 平台。
- 🔔 **阿里云推送**:深度集成阿里云官方推送 SDK,保证推送服务的稳定性和可靠性。
- 🔧 **简化接入**:封装原生复杂配置,提供简洁易用的 dart API。
- 🎯 **消息处理**:支持接收和处理通知栏消息及应用内消息。
- 🔌 **易于扩展**:未来可根据需求扩展更多推送相关功能。
## 3. 安装步骤
`pubspec.yaml`中加入dependencies
```yaml
dependencies:
aliyun_push: 1.0.0
```
## 4. 插件初始化
```dart
import 'package:aliyun_push/aliyun_push.dart';
final _aliyunPush = AliyunPush();
Future<void> initAliyunPush() async {
String appKey;
String appSecret;
// 配置App Key和App Secret(请在 https://emas.console.aliyun.com 获取)
if (Platform.isIOS) {
appKey = "填写自己iOS项目的appKey";
appSecret = "填写自己iOS项目的appSecret";
} else {
appKey = "填写自己Android项目的appKey";
appSecret = "填写自己Android项目的appSecret";
}
_aliyunPush
.initPush(appKey: appKey, appSecret: appSecret)
.then((initResult) {
var code = initResult['code'];
if (code == kAliyunPushSuccessCode) {
showOkDialog("初始化推送成功");
} else {
String errorMsg = initResult['errorMsg'];
showErrorDialog('初始化推送失败, errorMsg: $errorMsg}');
}
});
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
}
```
## 5. 原生环境配置
### 5.1 Android 配置
#### 5.1.1 配置 AndroidManifest 文件
`android/app/src/main/AndroidManifest.xml` 文件的 `<application>` 标签内,添加以下配置以支持多个推送通道(如华为、VIVO、荣耀、OPPO、小米、魅族及 FCM):
```xml
<!-- 华为推送 -->
<meta-data android:name="com.huawei.hms.client.appid" android:value="YOUR_HUAWEI_APP_ID" />
<!-- VIVO 推送 -->
<meta-data android:name="com.vivo.push.api_key" android:value="YOUR_VIVO_API_KEY" />
<meta-data android:name="com.vivo.push.app_id" android:value="YOUR_VIVO_APP_ID" />
<!-- 荣耀推送 -->
<meta-data android:name="com.hihonor.push.app_id" android:value="YOUR_HIHONOR_APP_ID" />
<!-- OPPO 推送 -->
<meta-data android:name="com.oppo.push.key" android:value="YOUR_OPPO_KEY" />
<meta-data android:name="com.oppo.push.secret" android:value="YOUR_OPPO_SECRET" />
<!-- 小米推送 -->
<meta-data android:name="com.xiaomi.push.id" android:value="YOUR_XIAOMI_APP_ID" />
<meta-data android:name="com.xiaomi.push.key" android:value="YOUR_XIAOMI_APP_KEY" />
<!-- 魅族推送 -->
<meta-data android:name="com.meizu.push.id" android:value="YOUR_MEIZU_APP_ID" />
<meta-data android:name="com.meizu.push.key" android:value="YOUR_MEIZU_APP_KEY" />
<!-- FCM 推送 -->
<meta-data android:name="com.gcm.push.sendid" android:value="YOUR_FCM_SENDER_ID" />
<meta-data android:name="com.gcm.push.applicationid" android:value="YOUR_FCM_APP_ID" />
<meta-data android:name="com.gcm.push.projectid" android:value="YOUR_FCM_PROJECT_ID" />
<meta-data android:name="com.gcm.push.api.key" android:value="YOUR_FCM_API_KEY" />
<!-- 阿里云推送消息接收器(用户可自主扩展) -->
<receiver android:name="com.aliyun.ams.push.AliyunPushMessageReceiver" android:exported="false">
<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>
```
**注意事项**
- **替换参数**:将 `YOUR_XXX` 占位符替换为各推送平台提供的实际参数(如 App ID、API Key 等)。请参考[阿里云推送官方文档](https://help.aliyun.com/document_detail/434677.html)获取具体配置方法。
- **消息接收器**:本插件已内置 `AliyunPushMessageReceiver`,只需按上述模板添加 `<receiver>` 配置即可支持通知的接收和处理。
- **权限检查**:确保 `AndroidManifest.xml` 已包含必要的网络和推送相关权限(如 `<uses-permission android:name="android.permission.INTERNET" />`)。
以下3个通道配置时需要特殊处理
+ 华为通道的`com.huawei.hms.client.appid`参数值的格式是`appid=xxxx`,有个前缀`appid=`
+ 小米通道的`com.xiaomi.push.id``com.xiaomi.push.key`的值一般都是长数字,如果直接配置原始值,系统读取时会自动判断成long类型,但是AndroidManifest中的meta-data是不支持long类型的,这样就会造成插件读取到的值和实际值不一致,进而导致小米通道初始化失败
+ fcm通道的`com.gcm.push.sendid`值也是长数字,同样会导致插件读取时出错
解决办法:
+ 配置时在原始值前方加入`id=`,插件会自动解析并读取原始值
```xml
<application android:name="*****">
<!-- 小米-->
<meta-data android:name="com.xiaomi.push.id" android:value="id=2222222222222222222" />
<meta-data android:name="com.xiaomi.push.key" android:value="id=5555555555555" />
<!-- fcm -->
<meta-data android:name="com.gcm.push.sendid" android:value="id=999999999999" />
</application>
```
#### 5.1.2 混淆配置
如果您的项目中使用Proguard等工具做了代码混淆,请保留以下配置:
```txt
-keepclasseswithmembernames class ** {
native <methods>;
}
-keepattributes Signature
-keep class sun.misc.Unsafe { *; }
-keep class com.taobao.** {*;}
-keep class com.alibaba.** {*;}
-keep class com.alipay.** {*;}
-keep class com.ut.** {*;}
-keep class com.ta.** {*;}
-keep class anet.**{*;}
-keep class anetwork.**{*;}
-keep class org.android.spdy.**{*;}
-keep class org.android.agoo.**{*;}
-keep class android.os.**{*;}
-keep class org.json.**{*;}
-dontwarn com.taobao.**
-dontwarn com.alibaba.**
-dontwarn com.alipay.**
-dontwarn anet.**
-dontwarn org.android.spdy.**
-dontwarn org.android.agoo.**
-dontwarn anetwork.**
-dontwarn com.ut.**
-dontwarn com.ta.**
```
### 5.2 iOS 配置
#### 5.2.1 Podfile 仓库配置
打开 `ios/Podfile` 文件,在文件最上方添加阿里云仓库和官方仓库地址:
```ruby
source 'https://github.com/aliyun/aliyun-specs.git'
source 'https://github.com/CocoaPods/Specs.git'
```
然后进入 `ios` 目录执行 `pod install --repo-update`
**注意**:iOS 工程需在 Xcode 的 TARGETS -> Build Settings -> Linking -> Other Linker Flags 中添加 `-ObjC`,否则推送服务无法正常使用。
如工程依赖多个三方库,可能因 Category 冲突导致问题。此时可用 `-force_load` 单独载入指定二进制文件,例如:
```c++
-force_load<framework_path>/CloudPushSDK.framework/CloudPushSDK
```
## 6. API 参考
本节提供插件的 API 详细参考,涵盖初始化、通用、平台特定(Android 和 iOS)以及回调事件处理接口。每个 API 均包含用途、参数、返回值和使用示例。
### 6.1 初始化相关接口
#### setLogLevel
`Future<Map<dynamic, dynamic>> setLogLevel(AliyunPushLogLevel level) async`
设置推送SDK输出日志的级别
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| level | AliyunPushLogLevel | 必须参数 | `None``Debug``Info``Warn``Error`)。设置为 `None` 禁用日志,其他级别启用日志。|
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.setLogLevel(logLevel).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
} else {
var errorCode = result['code'];
var errorMsg = result['errorMsg'];
}
});
```
#### `initPush`
`Future<Map<dynamic, dynamic>> initPush({String? appKey, String? appSecret}) async`
参数:
| 参数名 | 类型 | 是否必须 |
| --- | --- | ---|
| appKey | String | 可选参数 |
| appSecret | String | 可选参数 |
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
String appKey;
String appSecret;
if (Platform.isIOS) {
appKey = "填写自己iOS项目的appKey";
appSecret = "填写自己iOS项目的appSecret";
} else {
appKey = "填写自己Android项目的appKey";
appSecret = "填写自己Android项目的appSecret";
}
_aliyunPush.initPush(appKey: appKey, appSecret: appSecret)
.then((initResult) {
var code = initResult['code'];
if (code == kAliyunPushSuccessCode) {
print('Init Aliyun Push successfully');
} else {
String errorMsg = initResult['errorMsg'];
print('Aliyun Push init failed, errorMsg is: $errorMsg);
}
```
### 6.2 通用接口
#### getDeviceId
`Future<String> getDeviceId()`
获取设备Id
返回值:
`String` - 设备Id
代码示例:
```dart
_aliyunPush.getDeviceId().then((deviceId) {
});
```
#### bindAccount
`Future<Map<dynamic, dynamic>> bindAccount(String account) async`
绑定账号
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| account | String | 必须参数 | 要绑定的账号 |
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码实例:
```dart
_pushPlugin.bindAccount(account).then((bindResult) {
var code = bindResult['code'];
if (code == kAliyunPushSuccessCode) {
} else {
}
});
```
#### unbindAccount
`Future<Map<dynamic, dynamic>> unbindAccount(String account) async`
解绑账号
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码实例:
```dart
_pushPlugin.unbindAccount(account).then((unbindResult) {
var code = unbindResult['code'];
if (code == kAliyunPushSuccessCode) {
} else {
}
});
```
#### `addAlias`
`Future<Map<dynamic, dynamic>> addAlias(String alias) async`
添加别名
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| alias | String | 必须参数 | 要添加的别名 |
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_pushPlugin.addAlias(account).then((addResult) {
var code = addResult['code'];
if (code == kAliyunPushSuccessCode) {
} else {
}
});
```
#### `removeAlias`
`Future<Map<dynamic, dynamic>> removeAlias(String alias) async`
移除别名
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| alias | String | 必须参数 | 要移除的别名 |
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_pushPlugin.removeAlias(account).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
} else {
}
});
```
#### `listAlias`
` Future<Map<dynamic, dynamic>> listAlias() async `
查询别名
返回值:
`Map<dynamic, dynamic>`
map中包含三个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
+ `aliasList`: 别名列表(以逗号拼接成字符串形式返回别名列表)
代码示例:
```dart
_pushPlugin.listAlias(account).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
var aliasList = result['aliasList'];
} else {
}
});
```
#### `bindTag`
`Future<Map<dynamic, dynamic>> bindTag(List<String> tags,{int target = kAliyunTargetDevice, String? alias}) async`
添加标签
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| tags | List\<String> | 必须参数 | 要绑定的标签列表 |
| target | int | 可选参数 | 目标类型,1: 本设备 2: 本设备绑定账号 3: 别名</br>默认是1 |
| alias | String| 可选参数 | 别名(仅当target = 3时生效)
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码实例:
```dart
_pushPlugin.bindTag(tags).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
} else {
}
});
```
#### `unbindTag`
`Future<Map<dynamic, dynamic>> unbindTag(List<String> tags, {int target = kAliyunTargetDevice, String? alias}) async`
移除标签
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| tags | List\<String\> | 必须参数 | 要移除的标签列表 |
| target | int | 可选参数 | 目标类型,1: 本设备 2: 本设备绑定账号 3: 别名</br>默认是1 |
| alias | String| 可选参数 | 别名(仅当target = 3时生效)
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码实例:
```dart
_pushPlugin.unbindTag(tags).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
} else {
}
});
```
#### `listTags`
`Future<Map<dynamic, dynamic>> listTags`
查询标签列表
返回值:
`Map<dynamic, dynamic>`
map中包含三个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
+ `tagsList`: 标签列表(以逗号拼接成字符串形式返回标签列表)
代码示例:
```dart
_pushPlugin.listTags(account).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
var tagsList = listTagsResult['tagsList'];
} else {
}
});
```
### 6.3 Android 专用接口
#### `initAliyunThirdPush`
`Future<Map<dynamic, dynamic>> initAndroidThirdPush() async`
**注意:**该方法只支持Android平台
初始化辅助通道
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.initAndroidThirdPush().then((initResult) {
var code = initResult['code'];
if (code == kAliyunPushSuccessCode) {
print("Init Aliyun Third Push successfully");
} else {
print( 'Aliyun Third Push init failed, errorMsg is: $errorMsg');
}
});
```
#### bindPhoneNumber
`Future<Map<dynamic, dynamic>> bindPhoneNumber(String phone) async`
绑定手机号码
> **注意:只支持Android平台**
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| phone | string | 必须参数 | 要绑定的电话号码|
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.bindPhoneNumber(phone).then((bindResult) {
var code = bindResult['code'];
if (code == kAliyunPushSuccessCode) {
} else {
var errorCode = bindResult['code'];
var errorMsg = bindResult['errorMsg'];
}
});
```
#### unbindPhoneNumber
`Future<Map<dynamic, dynamic>> unbindPhoneNumber() async`
解绑手机号码
> **注意:只支持Android平台**
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.unbindPhoneNumber().then((unbindResult) {
var code = unbindResult['code'];
if (code == kAliyunPushSuccessCode) {
} else {
var errorCode = unbindResult['code'];
var errorMsg = unbindResult['errorMsg'];
}
});
```
#### setNotificationInGroup
`Future<Map<dynamic, dynamic>> setNotificationInGroup(bool inGroup) async`
设置通知分组展示
> **注意:只支持Android平台**
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| inGroup | bool | 必须参数 | true-开启分组;false-关闭分组 |
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.setNotificationInGroup(true).then((result){
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
print('开启通知分组展示成功');
}
});
_aliyunPush.setNotificationInGroup(false).then((result){
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
print('关闭通知分组展示成功');
}
});
```
#### clearNotifications
`Future<Map<dynamic, dynamic>> clearNotifications() async`
清除所有通知
> **注意:只支持Android平台**
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.clearNotifications().then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
}
});
```
#### createAndroidChannel
`Future<Map<dynamic, dynamic>> createAndroidChannel(
String id, String name, int importance, String description,
{String? groupId,
bool? allowBubbles,
bool? light,
int? lightColor,
bool? showBadge,
String? soundPath,
int? soundUsage,
int? soundContentType,
int? soundFlag,
bool? vibration,
List<int>? vibrationPatterns})`
创建Android平台的NotificationChannel
> **注意:只支持Android平台**
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| id | String | 必须参数 | 通道id |
| name | String |必须参数 | 通道name |
| importance | int | 必须参数 | 通道importance |
| desc | String | 必须参数 | 通道描述 |
| groupId | String | 可选参数 | - |
| allowBubbles | bool | 可选参数 | - |
| light | bool | 可选参数 | - |
| lightColor | int | 可选参数 | - |
| showBadge | bool | 可选参数 | - |
| soundPath | String | 可选参数 | - |
| soundUsage | int | 可选参数 | - |
| soundContentType | int | 可选参数 | - |
| soundFlag | int | 可选参数 | - |
| vibration | bool | 可选参数 | - |
| vibrationPatterns | List\<int> | 可选参数 | - |
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.createAndroidChannel(_channelController.text, '测试通道A', 3, '测试创建通知通道')
.then((createResult) {
var code = createResult['code'];
if (code == kAliyunPushSuccessCode) {
Fluttertoast.showToast(
msg: '创建$channel通道成功', gravity: ToastGravity.CENTER);
} else {
var errorCode = createResult['code'];
var errorMsg = createResult['errorMsg'];
Fluttertoast.showToast(
msg: '创建$channel通道失败, $errorCode - $errorMsg',
gravity: ToastGravity.CENTER);
}
});
```
#### createAndroidChannelGroup
`Future<Map<dynamic, dynamic>> createAndroidChannelGroup(String id, String name, String desc) async`
创建通知通道的分组
> **注意:只支持Android平台**
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| id | String | 必须参数 | 通道id |
| name | String |必须参数 | 通道name |
| desc | String | 必须参数 | 通道描述 |
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
#### isAndroidNotificationEnabled
`Future<bool> isAndroidNotificationEnabled({String? id}) async`
检查通知状态
> **注意:只支持Android平台**
参数:
| 参数名 | 类型 | 是否必须 | 含义 |
| --- | --- | ---| --- |
| id | String | 可选参数 | 通道id |
返回值:
`bool` - true: 已打开; false:未打开
代码示例:
```dart
bool isEnabled = await _aliyunPush.isAndroidNotificationEnabled(
id: 'xxx');
```
#### jumpToAndroidNotificationSettings
`void jumpToAndroidNotificationSettings({String? id})`
跳转到通知设置页面
> **注意:只支持Android平台**
代码示例:
```dart
_aliyunPush.jumpToAndroidNotificationSettings();
```
### 6.4 iOS 专用接口
#### setIOSBadgeNum
`Future<Map<dynamic, dynamic>> setIOSBadgeNum(int num) async`
设置角标数
> **注意:只支持iOS平台**
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.setIOSBadgeNum(badgeNum).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Fluttertoast.showToast(
msg: '设置角标个数$badgeNum成功', gravity: ToastGravity.CENTER);
}
});
```
#### syncIOSBadgeNum
`Future<Map<dynamic, dynamic>> syncIOSBadgeNum(int num) async`
同步角标数
> **注意:只支持iOS平台**
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.syncIOSBadgeNum(badgeNum).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Fluttertoast.showToast(
msg: '同步角标个数$badgeNum成功', gravity: ToastGravity.CENTER);
}
});
```
#### getApnsDeviceToken
`Future<String> getApnsDeviceToken() async`
获取APNs Token
> **注意:只支持iOS平台**
返回值:
`String` - APNs Token
代码示例:
```dart
_aliyunPush.getApnsDeviceToken().then((token) {
});
```
#### showIOSNoticeWhenForeground
`Future<Map<dynamic, dynamic>> showIOSNoticeWhenForeground(bool enable) async`
App处于前台时显示通知
> **注意:只支持iOS平台**
返回值:
`Map<dynamic, dynamic>`
map中包含两个key值:
+ `code`: 错误码
+ `errorMsg`: 错误信息
代码示例:
```dart
_aliyunPush.showIOSNoticeWhenForeground(true).then((result) {
var code = result['code'];
if (code == kAliyunPushSuccessCode) {
Fluttertoast.showToast(
msg: '设置前台显示通知成功', gravity: ToastGravity.CENTER);
}
});
```
#### isIOSChannelOpened
`Future<bool> isIOSChannelOpened() async`
通知通道是否已打开
> **注意:只支持iOS平台**
返回值:
`bool` - true: 已打开; false:未打开
代码示例:
```dart
_aliyunPush.isIOSChannelOpened().then((opened) {
if (opened) {
} else {
}
});
```
### 6.5 回调事件处理
#### `addMessageReceiver`
```dart
void addMessageReceiver(
{PushCallback? onNotification,
PushCallback? onMessage,
PushCallback? onNotificationOpened,
PushCallback? onNotificationRemoved,
PushCallback? onAndroidNotificationReceivedInApp,
PushCallback? onAndroidNotificationClickedWithNoAction,
PushCallback? onIOSChannelOpened,
PushCallback? onIOSRegisterDeviceTokenSuccess,
PushCallback? onIOSRegisterDeviceTokenFailed})
```
注册推送相关的回调
参数:
| 参数名 | 类型 | 是否必须 | 支持平台 | 功能 |
| --- | --- | ---| --- | --- |
| onNotification | PushCallback | 可选参数 | Android/iOS | 收到通知的回调 |
| onMessage | PushCallback | 可选参数 | Android/iOS | 收到消息的回调 |
| onNotificationOpened | PushCallback | 可选参数 | Android/iOS | 从通知栏打开通知的扩展处理 |
| onNotificationRemoved | PushCallback | 可选参数 | Android/iOS | 通知删除回调 |
| onAndroidNotificationReceivedInApp | PushCallback | 可选参数 | Android | 应用处于前台时通知到达回调 |
| onAndroidNotificationClickedWithNoAction | PushCallback | 可选参数 | Android | 无动作通知点击回调。当在后台或阿里云控制台指定的通知动作为无逻辑跳转时, 通知点击回调为onNotificationClickedWithNoAction而不是onNotificationOpened |
| onIOSChannelOpened | PushCallback | 可选参数 | iOS | 通道channel打开的回调 |
| onIOSRegisterDeviceTokenSuccess | PushCallback | 可选参数 | iOS | 注册APNs token成功回调|
| onIOSRegisterDeviceTokenFailed | PushCallback | 可选参数 | iOS | 注册APNs token失败回调|
代码示例:
```dart
_aliyunPush.addMessageReceiver(
onNotification: _onNotification,
onNotificationOpened: _onNotificationOpened,
onNotificationRemoved: _onNotificationRemoved,
onMessage: _onMessage,
onAndroidNotificationReceivedInApp: _onAndroidNotificationReceivedInApp,
onAndroidNotificationClickedWithNoAction:
_onAndroidNotificationClickedWithNoAction,
onIOSChannelOpened: _onIOSChannelOpened,
onIOSRegisterDeviceTokenSuccess: _onIOSRegisterDeviceTokenSuccess,
onIOSRegisterDeviceTokenFailed: _onIOSRegisterDeviceTokenFailed);
```
### 6.6 常量和类型
#### 返回值Map结构
大多数API方法返回的'Map<dynamic, dynamic>'都包含以下标准字段:
| 字段名 | 类型 | 含义
| code | String | 错误码,成功时为"10000"
| errorMsg | String | 错误信息,成功时通常为空字符串或成功提示
部分方法可能包含额外的字段(如aliasList、tagsList等),具体请参考各方法的详细说明。
#### 结果状态码
| 名称 | 值 | 含义 |
| --- | --- | --- |
| kAliyunPushSuccessCode | "10000" | 成功 |
| kAliyunPushParamsIllegal | "10001" | 参数错误 |
| kAliyunPushFailedCode | "10002" | 通用失败码 |
| kAliyunPushOnlyAndroid | "10003" | 方法只支持Android平台|
| kAliyunPushOnlyIOS | "10004" | 方法只支持iOS平台 |
| kAliyunPushNotSupport | "10005" | 平台不支持,比如Android创建group只支持Android 8.0以上版本|
> 详细的原生SDK错误码请参考阿里云文档:[Android](https://help.aliyun.com/document_detail/434686.html), [iOS](https://help.aliyun.com/document_detail/434705.html)
#### 标签目标类型
- `kAliyunTargetDevice = 1`: 设备目标。
- `kAliyunTargetAccount = 2`: 账户目标。
- `kAliyunTargetAlias = 3`: 别名目标。
#### 类型定义
- **AliyunPushLogLevel**
```dart
enum AliyunPushLogLevel {
none('none'),
error('error'),
warn('warn'),
info('info'),
debug('debug');
final String value;
const AliyunPushLogLevel(this.value);
}
```
- **PushCallback**
```dart
typedef PushCallback = Future<dynamic> Function(Map<dynamic, dynamic> message);
```
## 7. 故障排查
1. **问题:iOS `pod install` 失败或找不到 `AlicloudPush` 模块。**
- **解决方案:**
1. 确保插件依赖已正确安装。
2. 尝试执行 `pod repo update` 更新本地 CocoaPods 仓库,然后再次 `pod install`。
3. 删除 `ios/Pods` 目录和 `ios/Podfile.lock` 文件,然后重新执行 `pod install`。
2. **问题:收不到推送通知。**
- **解决方案 (通用):**
1. 确认 AppKey 和 AppSecret (Android & iOS) 配置正确无误。
2. 检查设备网络连接是否正常。
3. 确认应用是否已获取到 Device ID (可以通过 API 获取并打印日志查看)。
4. 登录阿里云推送控制台,检查推送目标是否正确,是否有错误日志。
- **解决方案 (Android):**
1. 检查 `AndroidManifest.xml` 中的权限、Receiver 和 Meta-data 配置是否正确。
2. 查看 Logcat 日志,搜索 "MPS" 或 "AliPush" 等关键词,看是否有 SDK 初始化失败或连接错误的信息。
3. 如果使用厂商通道,确保已在阿里云控制台配置了对应厂商的参数,并且手机上安装了对应厂商的服务框架。
- **解决方案 (iOS):**
1. 确认已在 Xcode 中开启 "Push Notifications" Capability。
2. 确认推送证书 (开发/生产) 是否正确配置并上传到阿里云控制台,且未过期。
3. 真机调试时,检查设备的通知设置,确保允许该 App 显示通知。
3. **问题:如何在 Expo 框架中使用**
- **解决方案:**
1. 你需要参考[这篇文档](https://docs.expo.dev/develop/development-builds/create-a-build/)完成原生构建,并安装到调试机器替代 Expo Go 应用。
4. **问题:点击通知后,`onNotificationOpened` 事件没有触发。**
- **解决方案:**
1. **Android:** 确保在 `AndroidManifest.xml` 中注册了插件提供的 receiver 组件。
> 更多问题请参考[阿里云官网文档](https://help.aliyun.com/document_detail/434791.html)
## 8. 贡献指南
我们欢迎任何形式的贡献,包括但不限于:
- 报告 Bug (提交 Issue)
- 提交新功能建议 (提交 Issue)
- 编写或改进文档
- 提交 Pull Request (PR)
**提交 Issue:**
- 请先搜索已有的 Issue,避免重复提交。
- 清晰描述问题,提供复现步骤、环境信息 (Flutter 版本、库版本、iOS/Android 版本等) 和相关日志或截图。
**提交 Pull Request:**
1. Fork 本仓库。
2. 基于 `master` (或当前开发分支) 创建新的特性分支。
3. 确保代码风格一致 (可以使用 Prettier, ESLint 等工具)。
4. 提交 PR 到主仓库的 `master` 分支,并清晰描述 PR 的内容和目的。
## 9. 许可证
本库采用 [MIT License](LICENSE)
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
group 'com.aliyun.ams.push'
version '1.0'
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.0'
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
maven {
url 'https://maven.aliyun.com/nexus/content/repositories/releases/'
}
// 配置HMS Core SDK的Maven仓地址。
maven {
url 'https://developer.huawei.com/repo/'
}
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 36
namespace "com.aliyun.ams.push"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion 19
}
}
dependencies {
api 'com.aliyun.ams:alicloud-android-push:3.8.7'
api "com.aliyun.ams:alicloud-android-third-push:3.8.7"
api "com.aliyun.ams:alicloud-android-third-push-meizu:3.8.7"
api "com.aliyun.ams:alicloud-android-third-push-vivo:3.8.7"
api "com.aliyun.ams:alicloud-android-third-push-oppo:3.8.7"
api "com.aliyun.ams:alicloud-android-third-push-xiaomi:3.8.7"
api "com.aliyun.ams:alicloud-android-third-push-huawei:3.8.7"
api "com.aliyun.ams:alicloud-android-third-push-honor:3.8.7"
api 'com.aliyun.ams:alicloud-android-third-push-fcm:3.8.7'
}
rootProject.name = 'push'
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.aliyun.ams.push">
</manifest>
package com.aliyun.ams.push;
import android.util.Log;
/**
* @author wangyun
* @date 2023/1/18
*/
public class AliyunPushLog {
private static boolean sLogEnabled = false;
public static boolean isLogEnabled() {
return sLogEnabled;
}
public static void setLogEnabled(boolean logEnabled) {
sLogEnabled = logEnabled;
}
public static void d(String tag, String msg) {
if (sLogEnabled) {
Log.d(tag, msg);
}
}
public static void e(String tag, String msg) {
if (sLogEnabled) {
Log.e(tag, msg);
}
}
}
package com.aliyun.ams.push;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.sdk.android.push.MessageReceiver;
import com.alibaba.sdk.android.push.notification.CPushMessage;
import com.alibaba.sdk.android.push.notification.NotificationConfigure;
import com.alibaba.sdk.android.push.notification.PushData;
import android.app.Notification;
import android.content.Context;
import android.util.Log;
import androidx.core.app.NotificationCompat;
/**
* @author wangyun
* @date 2023/1/12
*/
public class AliyunPushMessageReceiver extends MessageReceiver {
// 消息接收部分的LOG_TAG
public static final String REC_TAG = "MPS:receiver";
@Override
public NotificationConfigure hookNotificationBuild() {
return new NotificationConfigure() {
@Override
public void configBuilder(Notification.Builder builder, PushData pushData) {
AliyunPushLog.e(REC_TAG, "configBuilder");
}
@Override
public void configBuilder(NotificationCompat.Builder builder, PushData pushData) {
AliyunPushLog.e(REC_TAG, "configBuilder");
}
@Override
public void configNotification(Notification notification, PushData pushData) {
AliyunPushLog.e(REC_TAG, "configNotification");
}
};
}
@Override
public boolean showNotificationNow(Context context, Map<String, String> map) {
for (Map.Entry<String, String> entry : map.entrySet()) {
AliyunPushLog.e(REC_TAG, "key " + entry.getKey() + " value " + entry.getValue());
}
return super.showNotificationNow(context, map);
}
/**
* 推送通知的回调方法
*
* @param context
* @param title
* @param summary
* @param extraMap
*/
@Override
public void onNotification(Context context, String title, String summary,
Map<String, String> extraMap) {
Map<String, Object> arguments = new HashMap<>();
if (null != extraMap) {
arguments.putAll(extraMap);
} else {
}
arguments.put("title", title);
arguments.put("summary", summary);
AliyunPushPlugin.sInstance.callFlutterMethod("onNotification", arguments);
}
/**
* 应用处于前台时通知到达回调。注意:该方法仅对自定义样式通知有效,相关详情请参考https://help.aliyun.com/document_detail/30066
* .html?spm=5176.product30047.6.620.wjcC87#h3-3-4-basiccustompushnotification-api
*
* @param context
* @param title
* @param summary
* @param extraMap
* @param openType
* @param openActivity
* @param openUrl
*/
@Override
protected void onNotificationReceivedInApp(Context context, String title, String summary,
Map<String, String> extraMap, int openType,
String openActivity, String openUrl) {
Map<String, Object> arguments = new HashMap<>();
if (extraMap != null && !extraMap.isEmpty()) {
arguments.putAll(extraMap);
}
arguments.put("title", title);
arguments.put("summary", summary);
arguments.put("openType", openType);
arguments.put("openActivity", openActivity);
arguments.put("openUrl", openUrl);
AliyunPushPlugin.sInstance.callFlutterMethod("onNotificationReceivedInApp", arguments);
}
/**
* 推送消息的回调方法
*
* @param context
* @param cPushMessage
*/
@Override
public void onMessage(Context context, CPushMessage cPushMessage) {
Map<String, Object> arguments = new HashMap<>();
arguments.put("title", cPushMessage.getTitle());
arguments.put("content", cPushMessage.getContent());
arguments.put("msgId", cPushMessage.getMessageId());
arguments.put("appId", cPushMessage.getAppId());
arguments.put("traceInfo", cPushMessage.getTraceInfo());
AliyunPushPlugin.sInstance.callFlutterMethod("onMessage", arguments);
}
/**
* 从通知栏打开通知的扩展处理
*
* @param context
* @param title
* @param summary
* @param extraMap
*/
@Override
public void onNotificationOpened(Context context, String title, String summary,
String extraMap) {
Map<String, Object> arguments = new HashMap<>();
arguments.put("title", title);
arguments.put("summary", summary);
arguments.put("extraMap", extraMap);
AliyunPushPlugin.sInstance.callFlutterMethod("onNotificationOpened", arguments);
}
/**
* 通知删除回调
*
* @param context
* @param messageId
*/
@Override
public void onNotificationRemoved(Context context, String messageId) {
Map<String, Object> arguments = new HashMap<>();
arguments.put("msgId", messageId);
AliyunPushPlugin.sInstance.callFlutterMethod("onNotificationRemoved", arguments);
}
/**
* 无动作通知点击回调。当在后台或阿里云控制台指定的通知动作为无逻辑跳转时,
* 通知点击回调为onNotificationClickedWithNoAction而不是onNotificationOpened
*
* @param context
* @param title
* @param summary
* @param extraMap
*/
@Override
protected void onNotificationClickedWithNoAction(Context context, String title, String summary
, String extraMap) {
Map<String, Object> arguments = new HashMap<>();
arguments.put("title", title);
arguments.put("summary", summary);
arguments.put("extraMap", extraMap);
AliyunPushPlugin.sInstance.callFlutterMethod("onNotificationClickedWithNoAction", arguments);
}
}
\ No newline at end of file
package com.aliyun.ams.push;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.sdk.android.push.CloudPushService;
import com.alibaba.sdk.android.push.CommonCallback;
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory;
import com.alibaba.sdk.android.push.noonesdk.PushInitConfig;
import android.app.Activity;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationManagerCompat;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
/**
* PushPlugin
*/
public class AliyunPushPlugin implements FlutterPlugin, MethodCallHandler {
private static final String TAG = "MPS:PushPlugin";
private static final String CODE_SUCCESS = "10000";
private static final String CODE_PARAM_ILLEGAL = "10001";
private static final String CODE_FAILED = "10002";
private static final String CODE_NOT_SUPPORT = "10005";
private static final String CODE_KEY = "code";
private static final String ERROR_MSG_KEY = "errorMsg";
private MethodChannel channel;
private Context mContext;
public static AliyunPushPlugin sInstance;
public AliyunPushPlugin() {
sInstance = this;
}
public void callFlutterMethod(String method, Map<String, Object> arguments) {
if (TextUtils.isEmpty(method)) {
return;
}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> channel.invokeMethod(method, arguments));
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "aliyun_push");
channel.setMethodCallHandler(this);
mContext = flutterPluginBinding.getApplicationContext();
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
String methodName = call.method;
if ("initPush".equals(methodName)) {
initPush(call, result);
} else if ("initThirdPush".equals(methodName)) {
initThirdPush(result);
} else if ("getDeviceId".equals(methodName)) {
getDeviceId(result);
} else if ("closePushLog".equals(methodName)) {
closePushLog(result);
} else if ("setLogLevel".equals(methodName)) {
setLogLevel(call, result);
} else if ("bindAccount".equals(methodName)) {
bindAccount(call, result);
} else if ("unbindAccount".equals(methodName)) {
unbindAccount(result);
} else if ("addAlias".equals(methodName)) {
addAlias(call, result);
} else if ("removeAlias".equals(methodName)) {
removeAlias(call, result);
} else if ("listAlias".equals(methodName)) {
listAlias(result);
} else if ("bindTag".equals(methodName)) {
bindTag(call, result);
} else if ("unbindTag".equals(methodName)) {
unbindTag(call, result);
} else if ("listTags".equals(methodName)) {
listTags(call, result);
} else if ("bindPhoneNumber".equals(methodName)) {
bindPhoneNumber(call, result);
} else if ("unbindPhoneNumber".equals(methodName)) {
unbindPhoneNumber(result);
} else if ("setNotificationInGroup".equals(methodName)) {
setNotificationInGroup(call, result);
} else if ("clearNotifications".equals(methodName)) {
clearNotifications(result);
} else if ("createChannel".equals(methodName)) {
createChannel(call, result);
} else if ("createGroup".equals(methodName)) {
createGroup(call, result);
} else if ("isNotificationEnabled".equals(methodName)) {
try {
isNotificationEnabled(call, result);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else if ("jumpToNotificationSettings".equals(methodName)) {
if (VERSION.SDK_INT >= VERSION_CODES.O) {
jumpToAndroidNotificationSettings(call);
}
} else if ("setPluginLogEnabled".equals(methodName)) {
Boolean enabled = call.argument("enabled");
if (enabled != null) {
AliyunPushLog.setLogEnabled(enabled);
}
} else {
result.notImplemented();
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
private void initPush(MethodCall call, Result result) {
String appKey = call.argument("appKey");
String appSecret = call.argument("appSecret");
if (TextUtils.isEmpty(appKey) || TextUtils.isEmpty(appSecret) || !(mContext instanceof Application)) {
PushServiceFactory.init(mContext);
} else {
PushInitConfig config = new PushInitConfig.Builder()
.application((Application) mContext)
.appKey(appKey)
.appSecret(appSecret)
.build();
PushServiceFactory.init(config);
}
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.setLogLevel(CloudPushService.LOG_DEBUG);
pushService.register(mContext, new CommonCallback() {
@Override
public void onSuccess(String response) {
HashMap<String, String> map = new HashMap<>();
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMessage) {
HashMap<String, String> map = new HashMap<>();
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMessage);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
private void initThirdPush(Result result) {
HashMap<String, String> map = new HashMap<>();
Context context = mContext.getApplicationContext();
if (context instanceof Application) {
Application application = (Application)context;
AliyunThirdPushUtils.registerHuaweiPush(application);
AliyunThirdPushUtils.registerXiaoMiPush(application);
AliyunThirdPushUtils.registerVivoPush(application);
AliyunThirdPushUtils.registerOppoPush(application);
AliyunThirdPushUtils.registerMeizuPush(application);
AliyunThirdPushUtils.registerGCM(application);
AliyunThirdPushUtils.registerHonorPush(application);
map.put(CODE_KEY, CODE_SUCCESS);
} else {
map.put(CODE_KEY, CODE_FAILED);
map.put(ERROR_MSG_KEY, "context is not Application");
}
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
private void closePushLog(Result result) {
CloudPushService service = PushServiceFactory.getCloudPushService();
service.setLogLevel(CloudPushService.LOG_OFF);
HashMap<String, String> map = new HashMap<>();
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
private void getDeviceId(Result result) {
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
String deviceId = pushService.getDeviceId();
try {
result.success(deviceId);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
private void setLogLevel(MethodCall call, Result result) {
try {
String level = call.argument("level");
if (level == null || level.isEmpty()) {
handleError(result, CODE_PARAM_ILLEGAL, "Log level is empty");
return;
}
Integer logLevel = getLogLevel(level.toLowerCase());
if (logLevel == null) {
handleError(result, CODE_PARAM_ILLEGAL, "Invalid log level: " + level);
return;
}
PushServiceFactory.getCloudPushService().setLogLevel(logLevel);
handleSuccess(result);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
handleError(result, CODE_FAILED, e.getMessage());
}
}
private Integer getLogLevel(String level) {
switch (level) {
case "none":
return CloudPushService.LOG_OFF;
case "error":
case "warn": // warn 映射为 error
return CloudPushService.LOG_ERROR;
case "info":
return CloudPushService.LOG_INFO;
case "debug":
return CloudPushService.LOG_DEBUG;
default:
return null;
}
}
private void handleSuccess(Result result) {
HashMap<String, String> map = new HashMap<>();
map.put(CODE_KEY, CODE_SUCCESS);
result.success(map);
}
private void handleError(Result result, String code, String errorMsg) {
HashMap<String, String> map = new HashMap<>();
map.put(CODE_KEY, code);
map.put(ERROR_MSG_KEY, errorMsg);
result.success(map);
}
private void bindAccount(MethodCall call, Result result) {
String account = call.argument("account");
HashMap<String, String> map = new HashMap<>();
if (TextUtils.isEmpty(account)) {
map.put(CODE_KEY, CODE_PARAM_ILLEGAL);
map.put(ERROR_MSG_KEY, "account can not be empty");
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.bindAccount(account, new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e){
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
}
private void unbindAccount(Result result) {
HashMap<String, String> map = new HashMap<>();
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.unbindAccount(new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
private void addAlias(MethodCall call, Result result) {
HashMap<String, String> map = new HashMap<>();
String alias = call.argument("alias");
if (TextUtils.isEmpty(alias)) {
map.put(CODE_KEY, CODE_PARAM_ILLEGAL);
map.put(ERROR_MSG_KEY, "alias can not be empty");
try {
result.success(map);
} catch (Exception e){
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.addAlias(alias, new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
}
private void removeAlias(MethodCall call, Result result) {
HashMap<String, String> map = new HashMap<>();
String alias = call.argument("alias");
if (TextUtils.isEmpty(alias)) {
map.put(CODE_KEY, CODE_PARAM_ILLEGAL);
map.put(ERROR_MSG_KEY, "alias can not be empty");
try {
result.success(map);
} catch (Exception e){
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.removeAlias(alias, new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e){
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
}
private void listAlias(Result result) {
HashMap<String, String> map = new HashMap<>();
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.listAliases(new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
map.put("aliasList", response);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
private void bindTag(MethodCall call, Result result) {
List<String> tags = call.argument("tags");
HashMap<String, String> map = new HashMap<>();
if (tags == null || tags.isEmpty()) {
map.put(CODE_KEY, CODE_PARAM_ILLEGAL);
map.put(ERROR_MSG_KEY, "tags can not be empty");
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
Integer target = call.argument("target");
if (target == null) {
//默认本设备
target = 1;
}
String alias = call.argument("alias");
String[] tagsArray = new String[tags.size()];
tagsArray = tags.toArray(tagsArray);
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.bindTag(target, tagsArray, alias, new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
}
private void unbindTag(MethodCall call, Result result) {
List<String> tags = call.argument("tags");
HashMap<String, String> map = new HashMap<>();
if (tags == null || tags.isEmpty()) {
map.put(CODE_KEY, CODE_PARAM_ILLEGAL);
map.put(ERROR_MSG_KEY, "tags can not be empty");
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
Integer target = call.argument("target");
if (target == null) {
//默认本设备
target = 1;
}
String alias = call.argument("alias");
String[] tagsArray = new String[tags.size()];
tagsArray = tags.toArray(tagsArray);
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.unbindTag(target, tagsArray, alias, new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
}
private void listTags(MethodCall call, Result result) {
Integer target = call.argument("target");
if (target == null) {
//默认本设备
target = 1;
}
HashMap<String, String> map = new HashMap<>();
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.listTags(target, new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
map.put("tagsList", response);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
private void bindPhoneNumber(MethodCall call, Result result) {
HashMap<String, String> map = new HashMap<>();
String phone = call.argument("phone");
if (TextUtils.isEmpty(phone)) {
map.put(CODE_KEY, CODE_PARAM_ILLEGAL);
map.put(ERROR_MSG_KEY, "phone number can not be empty");
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.bindPhoneNumber(phone, new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
}
private void unbindPhoneNumber(Result result) {
HashMap<String, String> map = new HashMap<>();
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.unbindPhoneNumber(new CommonCallback() {
@Override
public void onSuccess(String response) {
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
@Override
public void onFailed(String errorCode, String errorMsg) {
map.put(CODE_KEY, errorCode);
map.put(ERROR_MSG_KEY, errorMsg);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
});
}
private void setNotificationInGroup(MethodCall call, Result result) {
Boolean inGroup = call.argument("inGroup");
if (inGroup == null) {
inGroup = false;
}
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.setNotificationShowInGroup(inGroup);
HashMap<String, String> map = new HashMap<>();
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
private void clearNotifications(Result result) {
final CloudPushService pushService = PushServiceFactory.getCloudPushService();
pushService.clearNotifications();
HashMap<String, String> map = new HashMap<>();
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
private void createChannel(MethodCall call, Result result) {
HashMap<String, String> map = new HashMap<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String id = call.argument("id");
String name = call.argument("name");
Integer importance = call.argument("importance");
String desc = call.argument("desc");
String groupId = call.argument("groupId");
Boolean allowBubbles = call.argument("allowBubbles");
Boolean light = call.argument("light");
Integer color = call.argument("lightColor");
Boolean showBadge = call.argument("showBadge");
String soundPath = call.argument("soundPath");
Integer soundUsage = call.argument("soundUsage");
Integer soundContentType = call.argument("soundContentType");
Integer soundFlag = call.argument("soundFlag");
Boolean vibration = call.argument("vibration");
List<Long> vibrationPattern = call.argument("vibrationPattern");
NotificationManager notificationManager
= (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
int importanceValue;
if (importance == null) {
importanceValue = NotificationManager.IMPORTANCE_DEFAULT;
} else {
importanceValue = importance;
}
NotificationChannel channel = new NotificationChannel(id, name, importanceValue);
channel.setDescription(desc);
if (groupId != null) {
channel.setGroup(groupId);
}
if (allowBubbles != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
channel.setAllowBubbles(allowBubbles);
}
if (light != null) {
channel.enableLights(light);
}
if (color != null) {
channel.setLightColor(color);
}
if (showBadge != null) {
channel.setShowBadge(showBadge);
}
if (!TextUtils.isEmpty(soundPath)) {
File file = new File(soundPath);
if (file.exists() && file.canRead() && file.isFile()) {
if (soundUsage == null) {
channel.setSound(Uri.fromFile(file), null);
} else {
AudioAttributes.Builder builder = new AudioAttributes.Builder()
.setUsage(soundUsage);
if (soundContentType != null) {
builder.setContentType(soundContentType);
}
if (soundFlag != null) {
builder.setFlags(soundFlag);
}
channel.setSound(Uri.fromFile(file), builder.build());
}
}
}
if (vibration != null) {
channel.enableVibration(vibration);
}
if (vibrationPattern != null && vibrationPattern.size() > 0) {
long[] pattern = new long[vibrationPattern.size()];
for (int i = 0; i < vibrationPattern.size(); i++) {
pattern[i] = vibrationPattern.get(i);
}
channel.setVibrationPattern(pattern);
}
notificationManager.createNotificationChannel(channel);
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
map.put(CODE_KEY, CODE_NOT_SUPPORT);
map.put(ERROR_MSG_KEY,
"Android version is below Android O which is not support create channel");
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
}
private void createGroup(MethodCall call, Result result) {
HashMap<String, String> map = new HashMap<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String id = call.argument("id");
String name = call.argument("name");
String desc = call.argument("desc");
NotificationManager notificationManager
= (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannelGroup group = new NotificationChannelGroup(id, name);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
group.setDescription(desc);
}
notificationManager.createNotificationChannelGroup(group);
map.put(CODE_KEY, CODE_SUCCESS);
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
} else {
map.put(CODE_KEY, CODE_NOT_SUPPORT);
map.put(ERROR_MSG_KEY,
"Android version is below Android O which is not support create group");
try {
result.success(map);
} catch (Exception e) {
AliyunPushLog.e(TAG, Log.getStackTraceString(e));
}
}
}
private void isNotificationEnabled(MethodCall call, Result result) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager manager = (NotificationManager)mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
if (!manager.areNotificationsEnabled()) {
result.success(false);
return;
}
String id = call.argument("id");
if (id == null) {
result.success(true);
return;
}
List<NotificationChannel> channels = manager.getNotificationChannels();
for (NotificationChannel channel : channels) {
if (channel.getId().equals(id)) {
if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
result.success(false);
} else {
if (channel.getGroup() != null) {
if (android.os.Build.VERSION.SDK_INT
>= android.os.Build.VERSION_CODES.P) {
NotificationChannelGroup group
= manager.getNotificationChannelGroup(channel.getGroup());
result.success(!group.isBlocked());
return;
}
}
result.success(true);
return;
}
}
}
// channel 未定义,返回false
result.success(false);
} else {
boolean enabled = NotificationManagerCompat.from(mContext).areNotificationsEnabled();
result.success(enabled);
}
}
@RequiresApi(api = VERSION_CODES.O)
private void jumpToAndroidNotificationSettings(MethodCall call) {
String id = call.argument("id");
Intent intent;
if (id != null) {
intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, mContext.getPackageName());
intent.putExtra(Settings.EXTRA_CHANNEL_ID, id);
} else {
// 跳转到应用的通知设置界面
intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, mContext.getPackageName());
}
if (!(mContext instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
mContext.startActivity(intent);
}
}
package com.aliyun.ams.push;
import com.alibaba.sdk.android.push.HonorRegister;
import com.alibaba.sdk.android.push.huawei.HuaWeiRegister;
import com.alibaba.sdk.android.push.register.GcmRegister;
import com.alibaba.sdk.android.push.register.MeizuRegister;
import com.alibaba.sdk.android.push.register.MiPushRegister;
import com.alibaba.sdk.android.push.register.OppoRegister;
import com.alibaba.sdk.android.push.register.VivoRegister;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
/**
* @author wangyun
* @date 2023/1/13
*/
public class AliyunThirdPushUtils {
private static String getAppMetaDataWithId(Context context, String key) {
String value = getAppMetaData(context, key);
if (value != null && value.startsWith("id=")) {
return value.replace("id=", "");
}
return value;
}
public static String getAppMetaData(Context context, String key) {
try {
final PackageManager packageManager = context.getPackageManager();
final String packageName = context.getPackageName();
ApplicationInfo info = packageManager.getApplicationInfo(packageName,
PackageManager.GET_META_DATA);
if (info != null && info.metaData != null && info.metaData.containsKey(key)) {
return String.valueOf(info.metaData.get(key));
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
public static void registerGCM(Application application) {
String sendId = getGCMSendId(application);
String applicationId = getGCMApplicationId(application);
String projectId = getGCMProjectId(application);
String apiKey = getGCMApiKey(application);
if (sendId != null && applicationId != null && projectId != null && apiKey != null) {
GcmRegister.register(application, sendId, applicationId, projectId, apiKey);
}
}
private static String getGCMSendId(Context context) {
return getAppMetaDataWithId(context, "com.gcm.push.sendid");
}
private static String getGCMApplicationId(Context context) {
return getAppMetaDataWithId(context, "com.gcm.push.applicationid");
}
private static String getGCMProjectId(Context context) {
return getAppMetaDataWithId(context, "com.gcm.push.projectid");
}
private static String getGCMApiKey(Context context) {
return getAppMetaDataWithId(context, "com.gcm.push.api.key");
}
public static void registerMeizuPush(Application application) {
String meizuId = getMeizuPushId(application);
String meizuKey = getMeizuPushKey(application);
if (meizuId != null && meizuKey != null) {
MeizuRegister.register(application, meizuId, meizuKey);
}
}
private static String getMeizuPushId(Context context) {
return getAppMetaDataWithId(context, "com.meizu.push.id");
}
private static String getMeizuPushKey(Context context) {
return getAppMetaDataWithId(context, "com.meizu.push.key");
}
public static void registerOppoPush(Application application) {
String oppoKey = getOppoPushKey(application);
String oppoSecret = getOppoPushSecret(application);
if (oppoKey != null && oppoSecret != null) {
OppoRegister.register(application, oppoKey, oppoSecret);
}
}
private static String getOppoPushKey(Context context) {
return getAppMetaDataWithId(context, "com.oppo.push.key");
}
private static String getOppoPushSecret(Context context) {
return getAppMetaDataWithId(context, "com.oppo.push.secret");
}
public static void registerXiaoMiPush(Application application) {
String xiaoMiId = getXiaoMiId(application);
String xiaoMiKey = getXiaoMiKey(application);
if (xiaoMiId != null && xiaoMiKey != null) {
MiPushRegister.register(application, xiaoMiId, xiaoMiKey);
}
}
private static String getXiaoMiId(Context context) {
return getAppMetaDataWithId(context, "com.xiaomi.push.id");
}
private static String getXiaoMiKey(Context context) {
return getAppMetaDataWithId(context, "com.xiaomi.push.key");
}
public static void registerVivoPush(Application application) {
String vivoApiKey = getVivoApiKey(application);
String vivoAppId = getVivoAppId(application);
if (vivoApiKey != null && vivoAppId != null) {
VivoRegister.register(application);
}
}
private static String getVivoApiKey(Context context) {
return getAppMetaData(context, "com.vivo.push.api_key");
}
private static String getVivoAppId(Context context) {
return getAppMetaData(context, "com.vivo.push.app_id");
}
public static void registerHuaweiPush(Application application) {
String huaweiAppId = getHuaWeiAppId(application);
if (huaweiAppId != null) {
HuaWeiRegister.register(application);
}
}
private static String getHuaWeiAppId(Context context) {
String value = getAppMetaData(context, "com.huawei.hms.client.appid");
if (value != null && value.startsWith("appid=")) {
return value.replace("appid=", "");
}
return null;
}
public static void registerHonorPush(Application application) {
String honorAppId = getHonorAppId(application);
if (honorAppId != null) {
HonorRegister.register(application);
}
}
private static String getHonorAppId(Context context) {
return getAppMetaData(context, "com.hihonor.push.app_id");
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{"inputs":["/Users/shixiaochen/work/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","/Users/shixiaochen/work/project/aliyun_push_clx/example/.dart_tool/flutter_build/ffcd8e42a86383583ec4eae063f0ceb1/app.dill","/Users/shixiaochen/work/flutter/bin/internal/engine.version","/Users/shixiaochen/work/flutter/bin/internal/engine.version"],"outputs":["/Users/shixiaochen/work/project/aliyun_push_clx/example/build/ios/Release-iphoneos/App.framework/App"]}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.App.framework</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
No preview for this file type
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论