美文网首页Flutter
Flutter 集成《极光推送》点击消息解决方案

Flutter 集成《极光推送》点击消息解决方案

作者: 制造bug的大侠 | 来源:发表于2019-12-06 17:04 被阅读0次

    最近一个项目采用Flutter来开发,作为一个OC原生程序猿,也是心里没底,摸石头过河。结合各方文档趟了一把坑,把实际项目中遇到的坑记录一下。

    附上极光的sdk地址:https://github.com/jpush/jpush-flutter-plugin

    集成方法上面也有,该配证书配证书,该导依赖导依赖,就不赘述了。说说遇到的坑吧。

    补充一句,我在写文章的时候 JPush 是 0.3.0.


    一、接收推送

    未购买付费服务:由于系统机制不一样,当APP被杀死情况下,Android收不到,但是Android启动APP之后,能收到延迟的推送。Android退出不杀进程,依然能收到推送。IOS任何时候均能收到推送。

    大概原理就是,Android是通过极光的通信接受推送,需要APP进程存在才能收到推送。IOS是通过apns(和原生一样)。

    购买付费服务(未作真实测试,仅供参考):Android能通过 小米、华为等自家平台完成推送。



    二、点击推送

    重点内容来了,想要实现效果是,点击推送消息跳转到一个指定的页面。

    jpush.applyPushAuthority(        
        new NotificationSettingsIOS(sound: true, alert: true, badge: true));   
        try {      
            jpush.addEventHandler(        
            // 接收通知回调方法。        
            onReceiveNotification: (Map<String, dynamic> message) async {          
            },       
             // 点击通知回调方法。        
            onOpenNotification: (Map<String, dynamic> message) async {          
             },       
             // 接收自定义消息回调方法。        
            onReceiveMessage: (Map<String, dynamic> message) async {         
             },   );    
        } on PlatformException {      
            debugPrint('Failed to get platform version.');    
        } 
    );

    两种情况:

    1 APP活跃,收到消息,点击正常执行。校验登录情况,是否允许push到指定页面。

    void jump() {           
        Navigator.push(
            context,            
            new MaterialPageRoute(builder: (context) => NotificationsPage())
        );   
    }


    2 APP被杀死,IOS能收到,点击消息不执行。Android由于收不到消息,不存在这个情况。如果是付费服务,收到推送消息,理论上能执行,没有实际测试过。

    现在问题就只有一个,IOS通过消息启动APP,怎么能执行跳转。最后查阅了文档,看到了一个方法。

    ///
    /// iOS Only  
    /// 点击推送启动应用的时候原生会将该 notification 缓存起来,该方法用于获取缓存 notification 
    /// 注意:notification 可能是 remoteNotification 和 localNotification,两种推送字段不一样。 
    /// 如果不是通过点击推送启动应用,比如点击应用 icon 直接启动应用,notification 会返回 @{}。 
    /// @param {Function} callback = (Object) => {}  
    ///  
    Future<Map<dynamic, dynamic>> getLaunchAppNotification() async {    
        print(flutter_log + "getLaunchAppNotification:");    
        final Map<dynamic, dynamic> result = await _channel.invokeMethod('getLaunchAppNotification');
        return result;  
    }

    于是就有了一个思路。

    APP启动的时候创建一个单例,单例需要缓存主视图的context,以便于push时候使用,比如 登录后的home页面的context,点击消息时,由home页面push到Tag页面。同时需要做个标记,记录点击事件,是否已经被执行了。而点击通知是需要将标记状态做个更改。如果是IOS消息启动,直接执行push。

    class TaskNotifcation {
        int read = 0;  
        BuildContext _context;
        
        ///     实现单例
        ///     .........
        ///
        
        // 点击时使用
        void checkNotifcation() {   
            if (read == null || read == 0) {      
                read = 1;    
            } else {      
                read++;   
            }   
            if (Platform.isIOS) {     
                 jpush.setBadge(0);   
            }    
            jump(); 
        }
        
        // 主视图加载完成时候,赋值获取context
        void runTask(BuildContext context) async {    
            if (_context == null) {      
                _context = context;     
                if (Platform.isIOS) {        
                    final map = await jpush.getLaunchAppNotification();        
                    if (map != null && map.isNotEmpty) {          
                        read = 1;        
                    }     
                }     
                jump();    
            }  
        }

        void jump(){
                // TODO
        }
    }

    jump也要做相应的验证,同时把状态复位。延迟是为了动画执行,避免一闪而过(其实没什么用)。

    void jump() {    
        if (_context != null && read > 0) {      
            read = 0;      
            Future.delayed(Duration(milliseconds: 300), () {        
                Navigator.push(_context,            
                new MaterialPageRoute(builder: (context) => NotificationsPage()));      
            });    
        }  

    main.dart 修改点击事件。TaskNotifcation 一定要是单例,单例的写法不用我教吧。( 这个延迟有用吗??)

    onOpenNotification: (Map<String, dynamic> message) async {                       Future.delayed(Duration(seconds: 1), () {            
            TaskNotifcation.instance.checkNotifcation();          
         });        
    },

    在home.dart 里,页面加载完成是赋值context

    @override  
    Widget build(BuildContext context) {         
        TaskNotifcation.instance.runTask(context);    //传入context,并校验启动来源
        return Scaffold(
            /// widget 视图
        );
    }

    到这里推送点击基本就OK了,点击事件都交由TaskNotifcation去管理了,可以在里面加入别的业务逻辑,或更多判断。但由于他是单例,存下来的context不会被释放,所以还要在home.dart里加上:

    @override  void dispose() {    
        // TODO: implement dispose    
        super.dispose();    
        TaskNotifcation.instance.clearContext(); 
    }

    class TaskNotifcation{
         /// 其他代码
         ///......  
         /// jump(){};

        void clearContext(){    
            if (_context != null) {      
                _context = null;    
            }  
        }
    }

    我这里只提供思路和部分代码,具体怎么实现需要结合实际项目情况做调整,相信也有比我更好的方法。第一次写文档,不知道表诉清楚没有,欢迎留言。

    相关文章

      网友评论

        本文标题:Flutter 集成《极光推送》点击消息解决方案

        本文链接:https://www.haomeiwen.com/subject/lnjoettx.html