• Flutter集成个推推送-安卓原生篇


    请添加图片描述

    前言

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

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

    准备工作

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

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

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

    原生配置说明

    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
    <data android:host="host" android:path="path" android:scheme="scheme" />
    
    • 1

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

    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

    上路

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    // 通道名称
    protected var channel: String = "通道名称";
    
    // 获取推送,发给flutter
    protected var payLoad: String? = null;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    编写原生kotlin代码

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

    一、onCreate

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        // 获取自定义透传参数值
        val intent: Intent? = getIntent()
        if (null != intent) {
            payLoad = intent.getStringExtra("payload")
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    二、onNewIntent

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
    
        // 获取自定义透传参数值
        if (null != intent) {
            payLoad = intent.getStringExtra("payload")
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    三、configureFlutterEngine

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

    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) {}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    编写dart代码

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

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

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

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

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

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

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

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

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

    注意

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

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

    “{a: 1}”

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

    完整代码

    原生代码:

    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) {}
        }
    
    
    }
    
    
    • 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

    flutter代码:

    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;        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    最后

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

  • 相关阅读:
    触发点击事件,标签高亮显示
    c++编程实例
    MSTP+VRRP vlan接口作为网关(2)
    Python-爬虫(Scrapy爬虫框架,爬取豆瓣读书和评分)
    Spark Streaming(一)
    c++ 继承与多态
    docker使用入门
    【Redis】Redis内存模型
    vue高德地图JS API 实现海量点标记展示
    Spring Security 替换WebSecurityConfigurerAdapter (Deprecated)的方法
  • 原文地址:https://blog.csdn.net/qq_44500360/article/details/130385070