最近一個(gè)項(xiàng)目采用Flutter來(lái)開(kāi)發(fā)哮针,作為一個(gè)OC原生程序猿盆赤,也是心里沒(méi)底,摸石頭過(guò)河客们。結(jié)合各方文檔趟了一把坑,把實(shí)際項(xiàng)目中遇到的坑記錄一下材诽。
附上極光的sdk地址:https://github.com/jpush/jpush-flutter-plugin
集成方法上面也有底挫,該配證書(shū)配證書(shū),該導(dǎo)依賴導(dǎo)依賴脸侥,就不贅述了建邓。說(shuō)說(shuō)遇到的坑吧。
補(bǔ)充一句睁枕,我在寫(xiě)文章的時(shí)候 JPush 是 0.3.0.
一官边、接收推送
未購(gòu)買(mǎi)付費(fèi)服務(wù):由于系統(tǒng)機(jī)制不一樣,當(dāng)APP被殺死情況下外遇,Android收不到注簿,但是Android啟動(dòng)APP之后,能收到延遲的推送跳仿。Android退出不殺進(jìn)程诡渴,依然能收到推送。IOS任何時(shí)候均能收到推送菲语。
大概原理就是妄辩,Android是通過(guò)極光的通信接受推送惑灵,需要APP進(jìn)程存在才能收到推送。IOS是通過(guò)apns(和原生一樣)眼耀。
購(gòu)買(mǎi)付費(fèi)服務(wù)(未作真實(shí)測(cè)試英支,僅供參考):Android能通過(guò) 小米、華為等自家平臺(tái)完成推送哮伟。
二干花、點(diǎn)擊推送
重點(diǎn)內(nèi)容來(lái)了,想要實(shí)現(xiàn)效果是澈吨,點(diǎn)擊推送消息跳轉(zhuǎn)到一個(gè)指定的頁(yè)面把敢。
jpush.applyPushAuthority(????????
????new?NotificationSettingsIOS(sound:?true,?alert:?true,?badge:?true));???
????try?{??????
????????jpush.addEventHandler(????????
????????//?接收通知回調(diào)方法。????????
????????onReceiveNotification:?(Map<String,?dynamic>?message)?async?{??????????
????????},???????
?????????//?點(diǎn)擊通知回調(diào)方法谅辣。????????
????????onOpenNotification:?(Map<String,?dynamic>?message)?async?{??????????
?????????},???????
?????????//?接收自定義消息回調(diào)方法修赞。????????
????????onReceiveMessage:?(Map<String,?dynamic>?message)?async?{?????????
? ? ? ? ?},???);????
????}?on?PlatformException?{??????
????????debugPrint('Failed?to?get?platform?version.');????
????}?
);
兩種情況:
1 APP活躍,收到消息桑阶,點(diǎn)擊正常執(zhí)行柏副。校驗(yàn)登錄情況,是否允許push到指定頁(yè)面蚣录。
void?jump()?{? ? ? ? ? ?
????Navigator.push(
????????context,????????????
????????new?MaterialPageRoute(builder:?(context)?=>?NotificationsPage())
????);? ?
}
2 APP被殺死割择,IOS能收到,點(diǎn)擊消息不執(zhí)行萎河。Android由于收不到消息荔泳,不存在這個(gè)情況。如果是付費(fèi)服務(wù)虐杯,收到推送消息玛歌,理論上能執(zhí)行,沒(méi)有實(shí)際測(cè)試過(guò)擎椰。
現(xiàn)在問(wèn)題就只有一個(gè)支子,IOS通過(guò)消息啟動(dòng)APP,怎么能執(zhí)行跳轉(zhuǎn)达舒。最后查閱了文檔值朋,看到了一個(gè)方法。
///
///?iOS?Only??
///?點(diǎn)擊推送啟動(dòng)應(yīng)用的時(shí)候原生會(huì)將該?notification?緩存起來(lái)巩搏,該方法用于獲取緩存?notification?
///?注意:notification?可能是?remoteNotification?和?localNotification昨登,兩種推送字段不一樣。?
///?如果不是通過(guò)點(diǎn)擊推送啟動(dòng)應(yīng)用贯底,比如點(diǎn)擊應(yīng)用?icon?直接啟動(dòng)應(yīng)用篙骡,notification?會(huì)返回?@{}。?
///?@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;??
}
于是就有了一個(gè)思路。
APP啟動(dòng)的時(shí)候創(chuàng)建一個(gè)單例糯俗,單例需要緩存主視圖的context,以便于push時(shí)候使用尿褪,比如 登錄后的home頁(yè)面的context,點(diǎn)擊消息時(shí)得湘,由home頁(yè)面push到Tag頁(yè)面杖玲。同時(shí)需要做個(gè)標(biāo)記,記錄點(diǎn)擊事件淘正,是否已經(jīng)被執(zhí)行了摆马。而點(diǎn)擊通知是需要將標(biāo)記狀態(tài)做個(gè)更改。如果是IOS消息啟動(dòng)鸿吆,直接執(zhí)行push囤采。
class?TaskNotifcation?{
? ? int?read?=?0;??
????BuildContext?_context;
? ??
? ? ///? ? ?實(shí)現(xiàn)單例
? ? ///? ? ?.........
? ? ///
? ??
? ? // 點(diǎn)擊時(shí)使用
????void checkNotifcation()?{???
????????if?(read?==?null?||?read?==?0)?{??????
????????????read?=?1;????
????????}?else?{??????
????????????read++;???
? ? ????}???
? ? ????if?(Platform.isIOS)?{?????
?????????????jpush.setBadge(0);???
? ? ????}????
????????jump();?
????}
? ??
? ? // 主視圖加載完成時(shí)候,賦值獲取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也要做相應(yīng)的驗(yàn)證惩淳,同時(shí)把狀態(tài)復(fù)位蕉毯。延遲是為了動(dòng)畫(huà)執(zhí)行,避免一閃而過(guò)(其實(shí)沒(méi)什么用)思犁。
void?jump()?{????
????if?(_context?!=?null?&&?read?>?0)?{??????
????????read?=?0;??????
????????Future.delayed(Duration(milliseconds:?300),?()?{????????
????????????Navigator.push(_context,????????????
? ? ? ? ????new?MaterialPageRoute(builder:?(context)?=>?NotificationsPage()));??????
????????});????
????}??
}?
main.dart 修改點(diǎn)擊事件代虾。TaskNotifcation 一定要是單例,單例的寫(xiě)法不用我教吧激蹲。( 這個(gè)延遲有用嗎棉磨??)
onOpenNotification:?(Map<String,?dynamic>?message)?async?{? ? ? ? ? ? ? ? ? ?????Future.delayed(Duration(seconds:?1),?()?{????????????
????????TaskNotifcation.instance.checkNotifcation();??????????
? ? ?});????????
},
在home.dart 里学辱,頁(yè)面加載完成是賦值context
@override??
Widget?build(BuildContext?context)?{?????????
????TaskNotifcation.instance.runTask(context);? ? //傳入context乘瓤,并校驗(yàn)啟動(dòng)來(lái)源
????return?Scaffold(
? ? ? ? /// widget 視圖
????);
}
到這里推送點(diǎn)擊基本就OK了,點(diǎn)擊事件都交由TaskNotifcation去管理了策泣,可以在里面加入別的業(yè)務(wù)邏輯凡橱,或更多判斷辆沦。但由于他是單例炸庞,存下來(lái)的context不會(huì)被釋放缴阎,所以還要在home.dart里加上:
@override??void?dispose()?{????
????//?TODO:?implement?dispose????
????super.dispose();????
????TaskNotifcation.instance.clearContext();?
}
class TaskNotifcation{
? ? ?/// 其他代碼
? ? ?///......??
? ? ?/// jump(){};
? ??void?clearContext(){????
????????if?(_context?!=?null)?{??????
????????????_context?=?null;????
????????}??
????}
}
我這里只提供思路和部分代碼汽抚,具體怎么實(shí)現(xiàn)需要結(jié)合實(shí)際項(xiàng)目情況做調(diào)整苟翻,相信也有比我更好的方法衰倦。第一次寫(xiě)文檔花鹅,不知道表訴清楚沒(méi)有发侵,歡迎留言交掏。