美文网首页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