前言

在众多的集成化推送中选择了个推,个推在flutter集成中还是比较简单的,只需要跟着官网一步一步走就可以了。今天这篇文章不涉及到flutter项目个推的集成,只是记录个推离线走安卓厂商时,进行获取一个离线的点击通知数据。

在个推的官网中提供的例子是java的,不符合我的意向,再加上flutter默认是kotlin的,所以本篇文章也是以kotlin的代码为主。

准备工作

项目以集成个推推送并配置好了个推的appId和各方厂商的appIdappKey等。

在服务端的推送代码配置中需要添加push_channel键值对,可以参考下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"push_channel":{
"android":{
"ups":{
"notification":{
"title":"标题",
"body":"内容",
"click_type":"intent",
"url": "", // 不填
"intent": ""
}
}
}
}
}

原生配置说明

intent 已下面这种为参考进行配置。

  • host: host。这个是自定义的想咋写就咋写。
  • scheme: 协议方案。这个是自定义的想咋写就咋写。
  • package: app 包名。
  • component: 是一个启动的 Activity。
  • payload: 自定义传递的参数。

intent://host?#Intent;scheme=scheme;launchFlags=0x4000000;package=package;component=component;S.payload=payload;S.gttask=;end

配置好的样子大概就是下面这个样子:

intent://host?#Intent;scheme=scheme;launchFlags=0x4000000;package=package;component=包名/包名.MainActivity;S.payload=payload;S.gttask=;end

我们需要在android/app/src/main/AndroidManifest.xmlactivity中找到你配置个推的那块添加下面这样一段代码:

  • host: 这里的host就是上文中配置的host
  • path: 这个可以随便写,根据自己需求来。
  • scheme: 也是上文中的scheme
1
<data android:host="host" android:path="path" android:scheme="scheme" />

大概就是下面这个样子的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
...
>
...


<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="host" android:path="path" android:scheme="scheme" />
</intent-filter>

...
</activity>

上面这样就已经配置好了,现在开始来写代码。

上路

打开项目的android/app/src/main/kotlin/com/xx/xx/MainActivity.kt文件,引入下面的依赖。

1
2
3
4
5
import android.content.Intent 
import android.os.Bundle
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.embedding.engine.FlutterEngine

然后在MainActivity类中申明通道名称和payload。

1
2
3
4
5
6
// 通道名称
protected var channel: String = "通道名称";

// 获取推送,发给flutter
protected var payLoad: String? = null;

编写原生kotlin代码

我们需要重写onCreateonNewIntentconfigureFlutterEngine这三个方法,我们自己进行重新就可以了,在创建的项目代码中是没有这三个方法的。

一、onCreate

1
2
3
4
5
6
7
8
9
10
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// 获取自定义透传参数值
val intent: Intent? = getIntent()
if (null != intent) {
payLoad = intent.getStringExtra("payload")
}
}

二、onNewIntent

1
2
3
4
5
6
7
8
9
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)

// 获取自定义透传参数值
if (null != intent) {
payLoad = intent.getStringExtra("payload")
}
}

三、configureFlutterEngine

这里我们设置一个名为getIntentData的方法名,并进行判断是否是传递的这个方法名,并进行相关处理。我们后面获取数据全靠它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)

payLoad = intent.getStringExtra("payload");

try {

// 通过MethodChannel调用通知flutter开启参数
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
channel
).setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
if (call.method == "getIntentData") {
result.success("$payLoad")
}
}

} catch (err: Exception) {}

}

编写dart代码

现在我们回到flutter层面,开始写dart的代码,并进行与我们写的通道进行通信。

申明一个getIntentFuture的异步函数,并创建通道。这里的通道名称一定要和上面我们写的原生通道名称一致,不然没法调用通信。

1
2
3
4
getIntent() async {
// 设置通道名称
const MethodChannel channel = MethodChannel("通道名称");
}

通过invokeMethod的形式去调用我们在原生方面外露的方法名。

1
String result = await channel.invokeMethod("getIntentData");

接下来判断result是否是正确的值,因为我这边在原生那边通信的时候是将它转成了一个字符串,所以我们判断的是否要以字符串的形式去判断。像下面这样。

1
if (['null'].contains(result)){}

当我们拿到合规正确的值过后就可以全程在flutter层面进行调用使用了。由于他是一个字符串,我需要将他转成Map的形式来方便使用。

1
2
3
4
5
try {
Map data = json.decode(result);
} catch (error) {
throw Exception('from-> $result to Map fail, incorrect format');
}

注意

我这里在服务端传递payload的数据时是一个被json化了的字符串,如果朋友你不是这种的字符串记得加处理哦。

如果不知道什么是被json化了的字符串,可以看下面这个:

“{a: 1}”

这个我们就写完啦。这个不能边跑边调试,需要每次以离线跑进行调试,还是稍微有点麻烦。只能以冷启动进行调试。

完整代码

原生代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package 包名

import io.flutter.embedding.android.FlutterActivity

import android.content.Intent
import android.os.Bundle
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.embedding.engine.FlutterEngine

class MainActivity: FlutterActivity() {

// 通道名称
protected var channel: String = "通道名称";

// 获取推送,发给flutter
protected var payLoad: String? = null;

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// 获取自定义透传参数值
val intent: Intent? = getIntent()
if (null != intent) {
payLoad = intent.getStringExtra("payload")
}
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)

// 获取自定义透传参数值
if (null != intent) {
payLoad = intent.getStringExtra("payload")
}
}

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)

payLoad = intent.getStringExtra("payload");

try {

// 通过MethodChannel调用通知flutter开启参数
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
channel
).setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
if (call.method == "getIntentData") {
result.success("$payLoad")
}
}

} catch (err: Exception) {}
}


}

flutter代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Future<Map<String, dynamic>> getIntent() async {
// 设置通道名称
const MethodChannel channel = MethodChannel("通道名称");

String result = await channel.invokeMethod("getIntentData");
Map<String, dynamic> resultData = {};

if (['null'].contains(result)){
return resultData;
}

try {
Map data = json.decode(result);
resultData = data as Map<String, dynamic>;
} catch (error) {
throw Exception('from-> $result to Map fail, incorrect format');
}

return resultData;
}

最后

以上就是本篇文章的全部内容,希望对此时此刻的你有所帮助。