相关文章
推送配置共三篇(如下链接) 【Flutter】极光推送配置流程(极光通道/华为厂商/IOS) 章一 【Flutter】极光推送配置流程(小米厂商通道) 章二 【Flutter】极光推送配置流程(VIVO/OPPO/荣耀厂商通道) 章三
极光通道(在线)
配置时间 2024年3月11日
创建应用
应用列表 - 创建应用
Android - 选中消息推送 - 下一步
创建Flutter项目
填写包名
创建完成
项目配置
运行命令行 flutter pub add jpush_flutter
Android -> app -> build.gradle 更改JPUSH_APPKEY的值
工具类注册JPush Android
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:jpush_flutter/jpush_flutter.dart';
class JPushUtil {
JPushUtil._internal();
static final _instance = JPushUtil._internal();
factory JPushUtil() => _instance;
final JPush jPush = JPush();
Future<void> initPlatformState() async {
String? platformVersion;
try {
jPush.addEventHandler(
onReceiveNotification: (message) async {
print("flutter onReceiveNotification: $message");
},
onOpenNotification: (message) async {
print("flutter onOpenNotification: $message");
},
onReceiveMessage: (message) async {
print("flutter onReceiveMessage: $message");
},
onReceiveNotificationAuthorization: (message) async {
print("flutter onReceiveNotificationAuthorization: $message");
},
onConnected: (message) {
print("flutter onConnected: $message");
return Future(() => null);
},
);
} on PlatformException {
platformVersion = 'Failed to get platform version.';
print(platformVersion);
}
jPush.isNotificationEnabled().then((bool value) {
print("通知授权是否打开: $value");
if (!value) {
Get.snackbar(
"提示",
"没有通知权限,点击跳转打开通知设置界面",
duration: const Duration(seconds: 6),
onTap: (_) {
jPush.openSettingsForNotification();
},
);
}
}).catchError((onError) {
print("通知授权是否打开: ${onError.toString()}");
});
jPush.enableAutoWakeup(enable: true);
jPush.setup(
appKey: '7f684a39ff1f95ef1657acdd',
production: true,
debug: true,
);
jPush.applyPushAuthority(
const NotificationSettingsIOS(
sound: true,
alert: true,
badge: true,
),
);
final rid = await jPush.getRegistrationID();
print("flutter getRegistrationID: $rid");
}
setAlias(String aliasStr) {
final alias = jPush.setAlias(aliasStr);
print("Alias is $alias");
}
}
main.dart
import 'package:demonstration_project/jPushUtil.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter 极光推送',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
JPushUtil().initPlatformState();
super.initState();
}
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text("极光推送配置"),
),
);
}
}
运行项目
运行项目在Android端,有getRegistrationID,则注册成功
测试接收推送之前,先打开接收通知的权限
在极光平台检测集成
推送消息
平台推送
直接在平台客户端输入对应的数值来推送消息
注:当APP被杀死后,极光通道的推送就不能及时收到了,所以要配置厂商通道
推送API
厂商通道(华为)
创建项目 创建应用
应用服务 - PUSH
继续
选择中国
开通推送服务
添加应用
输入相关信息
下载agconnect-services.json
放到应用级目录下
SHA256证书指纹
生成签名jks
生成签名文件的参考文档链接
创建新的Key
生成签名证书指纹
** keytool -list -v -keystore ./demostration_project_key.jks**
配置SHA256证书指纹
项目配置
若出现以下报错
修改Manifest.xml文件
修改android/build.gradle文件
buildscript {
ext.kotlin_version = '1.9.0'
repositories {
google()
mavenCentral()
// 配置HMS Core SDK的Maven仓地址。
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://developer.huawei.com/repo/' }
}
}
若出现以下报错
那说明漏了配置AGC插件,参考相关链接
接着添加依赖
dependencies {
// 极光推送 'cn.jiguang.sdk:jpush:5.2.3' 和 'cn.jiguang.sdk.plugin:huawei:5.2.3' 版本需一致
implementation 'cn.jiguang.sdk:jpush:5.2.3'
implementation 'com.huawei.agconnect:agconnect-core:1.8.1.300'
implementation 'com.huawei.hms:push:6.12.0.300'
implementation 'cn.jiguang.sdk.plugin:huawei:5.2.3' // 这里版本一定要和极光插件版本一致!!!
}
最后配置签名文件,若出现以下错误,就代表没有配置签名
signingConfigs {
debug {
//keystore中key的别名
keyAlias 'demo_key'
//keystore中key的密码
keyPassword '123456'
//keystore的文件路径,可以是绝对路径也可以是相对路径
storeFile file('../demostration_project_key.jks')
//keystore的密码l
storePassword '123456'
}
}
最后在极光平台厂商通道配置设置App ID 和App Secret,并启用
华为平台配置
回执配置参考链接
这里的自分类是华为控制滥发消息的,需要设置一下,参考链接
选一个要发的场景
填写信息,和场景相关的信息
激活功能
找一台华为手机来运行项目
若出现以下这句,就代表配置成功了
这里的检测会有延迟,真机测试能离线收到消息就ok
错误集锦
1、版本不一致
1、极光厂商插件版本和JPush版本不一致,即便输出huawei token,也是收不到离线消息的
// 极光推送 'cn.jiguang.sdk:jpush:5.2.3' 和 'cn.jiguang.sdk.plugin:huawei:5.2.3' 版本需一致
implementation 'cn.jiguang.sdk:jpush:5.2.3'
// 华为
implementation 'com.huawei.agconnect:agconnect-core:1.8.1.300'
implementation 'com.huawei.hms:push:6.12.0.300'
implementation 'cn.jiguang.sdk.plugin:huawei:5.2.3'
2、权限
网络权限记得加上
<uses-permission android:name="android.permission.INTERNET" />
Ios
Push
Podfile
pod 'JPush'
pod 'JOperate'
pod 'JCore'
终端 pod install
Token Authentication配置
developer.apple.com
后续步骤直接参考上面的链接,很详细
最后获取到的
运行项目
配置完成
推送API
鉴权方式
用冒号拼接appkey和masterSecret,并用base64加密该字符串,最终再拼上"Basic "
final content = utf8.encode("$appKey:$masterSecret");
String base64AuthString = "Basic ${base64Encode(content)}";
测试代码
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '推送',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: '信息推送'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final String appKey = "XXX";
final String masterSecret = "XXX";
late String base64AuthString;
final Dio dio = Dio();
late String notificationAlert;
late String notificationTitle;
late String notificationAudienceAlias;
@override
void initState() {
final content = utf8.encode("$appKey:$masterSecret");
base64AuthString = "Basic ${base64Encode(content)}";
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
TextField(
decoration: const InputDecoration(
labelText: "主标题",
hintText: "请输入...",
),
onChanged: (s) {
notificationAlert = s;
},
),
TextField(
decoration: const InputDecoration(
labelText: "副标题",
hintText: "请输入...",
),
onChanged: (s) {
notificationTitle = s;
},
),
TextField(
decoration: const InputDecoration(
labelText: "别名",
hintText: "请输入...",
),
onChanged: (s) {
notificationAudienceAlias = s;
},
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: const Text("确定发送?"),
children: [
SimpleDialogOption(
child: const Text("确定"),
onPressed: () {
pushMessage(
notificationAlert: notificationAlert,
notificationTitle: notificationTitle,
notificationAudienceAlias: [
notificationAudienceAlias
],
);
Navigator.of(context).pop();
},
),
SimpleDialogOption(
child: const Text("取消"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
},
child: const Text("推送消息"),
),
),
],
),
),
),
);
}
/// 推送
pushMessage({
required String notificationAlert,
required String notificationTitle,
required List<String> notificationAudienceAlias,
}) async {
const String url = "https://api.jpush.cn/v3/push";
var data = json.encode({
"platform": ["android", "ios"],
"inapp_message": {"inapp_message": false},
"options": {
"classification": 0,
"time_to_live": 86400,
"apns_production": false,
"third_party_channel": {
"huawei": {
"skip_quota": false,
"distribution": "secondary_push",
"channel_id": "",
"category": "DEVICE_REMINDER",
"receipt_id": ""
}
}
},
"notification": {
"alert": notificationAlert,
"android": {
"alert": notificationAlert,
"title": notificationTitle,
"intent": {"url": "intent:#Intent;action=android.intent.action.MAIN;end"},
"sound": "",
"priority": 0,
"category": "",
"alert_type": 7,
"style": 0,
"builder_id": 0,
"large_icon": "",
"badge_add_num": 1,
"extras": {
"param": "123"
}
},
"ios": {
"alert": {
"title": notificationAlert,
"body": notificationTitle,
},
"content-available": 0,
"mutable-content": 1,
"sound": "default",
"badge": "+1",
"thread-id": "",
"interruption-level": "active",
"filter-criteria": "",
"extras": {
"参数": "A"
}
}
},
"audience": {
"alias": notificationAudienceAlias,
}
});
final response = await dio.request(
url,
data: data,
options: Options(
headers: {
HttpHeaders.authorizationHeader: base64AuthString,
},
method: "POST",
),
);
print(response.data.toString());
}
}
极光插件
首先是极光插件,可以去更新,但要看更新了什么内容
看这个更新内容,JPush 5.2.4
记得在之前那篇blog,我写了5.2.3
所以在.gradle文件中,把版本提到5.2.4(这里我直接截)
配置小米厂商通道
小米是需要上架应用的,需要企业开发者。 以下截图和代码是公司的项目,部分地方就马赛克了
上架
需要公司提供资料(软著/APP备案等),上架可能会快一些(1天以上)
推送申请估计要点时间(3天以上)
通道要申请下来,这里的类别,记得按自己需要。
类别选择参考这篇
填完类别等信息后
这里的channel_ID记一下
这里的appKey AppSecret AppID对应极光那三个要填写的
名字都一样的,把内容填写进去,再开启
build.gradle
回到项目
看这篇文章
配置依赖
// 小米
implementation 'cn.jiguang.sdk.plugin:xiaomi:5.2.4.a'
小米参数
填写小米参数
用一台小米手机来运行项目
若出现
xiao mi push register success
就代表配置好了
调用API发送推送
这里的channel id是之前创建的通道的id
代码之前篇章一有贴过
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '推送',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: '信息推送'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final String appKey = "XXXX";
final String masterSecret = "XXXXXXX";
late String base64AuthString;
final Dio dio = Dio();
late String notificationAlert;
late String notificationTitle;
late String notificationAudienceAlias;
@override
void initState() {
final content = utf8.encode("$appKey:$masterSecret");
base64AuthString = "Basic ${base64Encode(content)}";
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
TextField(
decoration: const InputDecoration(
labelText: "主标题",
hintText: "请输入...",
),
onChanged: (s) {
notificationAlert = s;
},
),
TextField(
decoration: const InputDecoration(
labelText: "副标题",
hintText: "请输入...",
),
onChanged: (s) {
notificationTitle = s;
},
),
TextField(
decoration: const InputDecoration(
labelText: "别名",
hintText: "请输入...",
),
onChanged: (s) {
notificationAudienceAlias = s;
},
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: const Text("确定发送?"),
children: [
SimpleDialogOption(
child: const Text("确定"),
onPressed: () {
pushMessage(
notificationAlert: notificationAlert,
notificationTitle: notificationTitle,
notificationAudienceAlias: [
notificationAudienceAlias
],
);
Navigator.of(context).pop();
},
),
SimpleDialogOption(
child: const Text("取消"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
},
child: const Text("推送消息"),
),
),
],
),
),
),
);
}
/// 推送
pushMessage({
required String notificationAlert,
required String notificationTitle,
required List<String> notificationAudienceAlias,
}) async {
const String url = "https://api.jpush.cn/v3/push";
var data = json.encode({
"platform": ["android", "ios"],
"inapp_message": {"inapp_message": false},
"options": {
"classification": 0,
"time_to_live": 86400,
"apns_production": false,
"third_party_channel": {
"huawei": {
"skip_quota": false,
"distribution": "secondary_push",
"channel_id": "",
"category": "DEVICE_REMINDER",
"receipt_id": ""
},
"xiaomi": {
"channel_id": "XXXXXX",
"distribution": "secondary_push",
"skip_quota": false
}
}
},
"notification": {
"alert": notificationAlert,
"android": {
"alert": notificationAlert,
"title": notificationTitle,
"intent": {"url": "intent:#Intent;action=android.intent.action.MAIN;end"},
"sound": "",
"priority": 0,
"category": "",
"alert_type": 7,
"style": 0,
"builder_id": 0,
"large_icon": "",
"badge_add_num": 1,
"extras": {
"param": "123"
}
},
"ios": {
"alert": {
"title": notificationAlert,
"body": notificationTitle,
},
"content-available": 0,
"mutable-content": 1,
"sound": "default",
"badge": "+1",
"thread-id": "",
"interruption-level": "active",
"filter-criteria": "",
"extras": {
"参数": "A"
}
}
},
"audience": {
"alias": notificationAudienceAlias,
}
});
final response = await dio.request(
url,
data: data,
options: Options(
headers: {
HttpHeaders.authorizationHeader: base64AuthString,
},
method: "POST",
),
);
print(response.data.toString());
}
}
后台关闭APP,杀掉APP,再发送一下
手机收到就代表配置完成
遇到的问题
设置别名
这个是在公司项目里面遇到的 需求是这样的:注册好极光的插件之后,若用户登录之后,我需要给当前设备设置别名为手机号。 当调用
final value = await jPush.setAlias("17777777777");
这个问题目前解决的办法是在手机号前加了一些数字比如000001777777777,就可以了。不清楚原因,所以就先记录一下。
升级插件后的IOS端修改
之前前文(章二),有讲到把jpush插件升级到3.0.0
这样做,IOS 用pod install会出现一些版本问题。原因是JPUSH和JCore之前download下来的版本不匹配
这时候需要指定这两个的版本
这里看到之前更新的内容,指定JCore和JPush版本分别为4.6.2和5.2.4
修改ios端的Podfile文件
pod 'JPush', '~> 5.2.4'
pod 'JOperate'
pod 'JCore', '~> 4.6.2'
这样重新运行pod install之后
VIVO厂商配置
配置依赖
implementation 'cn.jiguang.sdk.plugin:vivo:5.2.4'
去VIVO的开放平台
VIVO需要上架和企业开发者账号,审核需要1-3天,自己提前去上架,上架流程基本和其他厂商差不多。上架好了之后,去消息推送
创建应用
创建之后,去应用信息
VIVO_APPKEY和VIVO_APPID
去极光推送设置里面填上所有信息
运行项目,让VIVO用户去安装
调用API,配置厂商通道的参数,分类看情况选择,但是运营消息会受限制
推送API
OPPO厂商通道
OPPO稍微多几步骤 参考这里
添加aar文件
把这个aar文件放进libs目录下,没有libs目录,就new一个
配置依赖和APPKEY等
配置依赖,复制文档中的即可,会提示你有新版本的依赖,选择新的就可以了
implementation 'cn.jiguang.sdk.plugin:oppo:5.2.4'
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'commons-codec:commons-codec:1.11'
implementation 'androidx.annotation:annotation:1.6.0'
OPPO也是需要上架应用的,但审核会较快。多和客服交流,尽量两三次就上架好
到这里有上线的应用后
开通消息推送
创建通道
记一下通道ID
appkey、appsecret、masterSecret(appserversecret)
返回首页,进去看你的应用详情
到极光这里填写appkey、appsecret、masterSecret(appserversecret)
到项目的build中填写,记得加上OP-这个前缀
推送API
运行项目在OPPO手机上
调用API发送时,给参数多加个OPPO的参数配置,channel_id就是之前创建的通道ID,填进去
荣耀厂商通道配置
推送服务
签名指纹和华为厂商推送获取方式一致,上面的文档中也有
之前配置过华为厂商的,去华为那里看一下SHA256证书指纹,签名文件(jks)一样的话,直接复制SHA256指纹到荣耀申请推送服务要填写的地方
APP_ID等
回到项目去配置依赖,添加aar文件
荣耀厂商和华为厂商推送
运行项目在荣耀手机,注意如果荣耀是低版本,仍然采用华为推送
推送API
参数配置厂商通道
运行项目及注意事项
- 必须是对应厂商生产的手机,如果要测试OPPO是否配置完成,就不要拿VIVO的来测
- 通知权限都开了不,没有通知权限,那还测个屁
- 通知有可能在不重要通知中,仔细检查,没准通知躲在里面。
- 通知发太多,被限制数量了?
- 目前我用的极光版本SDK都是5.2.4,这个一定要一致!
- 建议使用API来测试,可以看这个文档官方推送API接口文档
- 极光有个检测配置是否成功的功能,建议自己发一遍推送后,再检测。同时,这个智能诊断会有延迟的,所以不能全信。当然公司不提供对应厂商的手机(比如我这个垃圾公司),那就只能信这个了,也许过几天就好了。我觉得是有人下了我的这个软件,正好他的手机是某某厂商的,注册好了SDK,所以就有了。
- 极光平台上有个可以查看原因的地方,也许没有收到通知的话就可以在这里找找原因
比如我这里就看到,有些用户并没有打开通知等
- 最后智能检测一下
当看到这里的智能诊断都ok了,基本就是没问题了,还差一个魅族,下一篇文章见啦!
关于推送的隐私协议
如果要上架应用,那么请务必记得要更新隐私协议(比如以上的各类推送的SDK,都需要在隐私协议里面详细说明,否则上架会被打回) 不过多打回几次也就有经验了,别问我怎么知道的
一些问题
检查这几个平台下的账号是不是都是企业开发者
结语
觉得写得还不错的话!给我点个赞吧~阿里嘎多~