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

最近一个项目采用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;    
        }  
    }
}

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269