Android推送的羣魔亂舞

前言

國內的Android推送就是個悲劇

國內Android缺乏Google的生態,如Google的Paly Store,Google Mobile Services(GSM)等,致使衍生出不少畸形的產業,好比五花八門的APP市場,光怪陸離的推送平臺,這裏要說的是推送平臺。Google自己的GSM服務是包含一套推送在裏面的,跟iOS系統的推送相似,它保證每臺手機維護一個推送通道就能收到各方推送,但因爲Google無法進入中國市場,國產Android基本上算被閹割了一個核心部件,由此衍生的種種弊端數不勝數,首當其衝的就是推送。html

國內的手機廠商基本都有自家的推送服務,來替代GSM的缺失,性能、用法良莠不齊。在離線場景下(APP死亡),若是想要收到推送,就必須接入對應廠家的推送服務,不然壓根收不到。因此Android APP在誕生之初基本就要集成華爲push、小米push、魅族push、oppo push、Vivo push等,相對GSM,複雜且沒有增益,就比如用江南七怪代替了黃老邪,難用的一B。然而,你別無選擇。不過國內各類廠商卻是樂此不疲,他們多了一個觸達用戶及統計的渠道,而且還能不受Google挾制,對於開發者而言,就要麻煩不少,工做量平白翻了不少倍;有的聊天APP爲了走自家的推送SDK,還要琢磨各類黑科技:包活,APP相互喚起等,惡之花,開的漫山遍野。更有意思的是,爲了解決這種問題,制定出規範,還促生個各類機構,像推送聯盟,綠色聯盟等,但並沒什麼卵用,成立3年,亂象依舊,不少說Android很垃圾,那推送的這個問題要負一大半責任。web

吐槽完,你仍然要接。後端

推送概念

爲何必定要接廠商的推送SDK呢?不接入收不到推送嗎?想要弄清這個東西,就要對推送有個簡單的瞭解,推送:它的點在推(push上,與其對應的是拉(Pull),核心就是客戶端跟服務器創建一個長連接,服務器會將信息分發到各個客戶端,簡化示意以下:服務器

對於手機端APP來講,推送分APP在線推送仍是離線推送,其實就是APP是否存活,APP存活狀況下,有多種選擇,若是APP經過Socket跟自家服務器創建了連接,則能夠由自家服務器直接推送到APP端,也能夠經過後端推送到第三方推送服務,藉由第三方推送給APP端,也就是在線狀況下,能夠不用接入第三方SDK。可是在APP死亡的狀況,只有一種方式:藉由第三方推送服務,推送給手機端,這種場景,APP必須接入第三方廠商SDK,拿華爲平臺爲例,其推送模型以下:markdown

華爲消息回執模式

與二者對應也有兩種消息的概念:透傳消息與通知欄消息:app

  • 透傳消息:APP存活狀況下,由推送服務直接把消息發送給APP應用,由APP本身選擇如何處理,注意透傳的前提是APP存活 ,透傳消息能夠不用接入第三方SDK。性能

  • 通知欄消息:在設備接收到消息以後,由系統彈出標準安卓通知,用戶點擊通知欄才激活應用,這種場景,APP無需存活(活着也不受影響),離線場景下,只有通知欄消息這一條路。ui

透傳消息每一個APP本身維護一條通道,離線消息只要一條系統通道,簡單看下二者對比,示意以下:url

對於在線透傳消息,因爲是在APP存活的狀況下收到的,APP端能夠統計到全部必要信息,不管是推送達時間、推送內容仍是通知的點擊都能統計到;可是離線推送就沒那麼幸運,不少信息APP本身是拿不到的,可是,業務方一般很是關心到達率、點擊率這些數據,必須有一個有效的解決方案。spa

推送統計問題 (離線推送)

如何到達率

這裏不考慮在線推送,只考慮離線(APP死亡),那麼離線推送APP能統計到達嗎?

答案是 不能,緣由其實很簡單,APP進程都死了,怎麼統計。這種狀況下,通知的展現屬於系統行爲,APP壓根沒法感知,更無從統計。不過,各三方推送服務平臺扔提供了推送到達統計的能力,即採用三方推送平臺的回執,以上面的華爲推送模型爲例:

華爲消息回執模式

能夠看到,離線推送的狀況下,華爲設備在展現完通知欄消息後,會給華爲Push服務一個回執,而華爲Push服務會把這個回執頭傳給開發者服務器,如此,APP服務端就能判斷推送是否到達。

如何統計點擊率

一樣,在離線推送的場景下,能統計到點擊事件嗎?關於這個場景,不一樣的廠商ROM及SDK真是亂七八糟,有的支持,有的不行,簡單整理下以下:

ROM 小米 華爲 魅族 oppo vivo
App是否能夠統計到離線點擊事件

所以,各方平臺給的方式並沒太多參考意義,必須經過其餘方式來統計點擊,離線推送基本都是經過scheme方式來處理,能夠經過加參數來搞定,後續詳述。

推送送達率=本次推送真正送達的設備數/所覆蓋的全部設備數(按理說,是應該清理掉無效設備)

哪些因素影響送達率

    1. 留存率。已經卸載了APP,確定收不到,可是有些三方平臺可能會歸結到分母中,須要自家後臺根據回執手動清理regID。
    1. 消息有效期,基本全部第三方PUSH平臺都支持設置有效期,有效期越短,觸達設備就越少,送達率會降低,能夠適當選擇有效時間。
    1. 聯網狀況, 在有效期內,設備沒聯網,也沒法送達,但會被計入分母
    1. 目標人羣設備的選取,活躍人羣設備送達率確定要高於全量推送

所以爲了能精準的計算送達率,APP服務端要按期清理無效regID(推送token),不然統計的送達率也會偏低

各離線推送平臺接入事項

不少大公司都有自家的推送SDK來處理透傳消息,小公司通常不具有這個能力,因此在接入Push的時候也分兩種狀況,

  • 1:有本身加的PushSDK,
  • 2:沒有自家PushSDK

若是APP有本身的PushSDK,那隻要接入第三方離線推送能力就行了,一些關於透傳的處理配置能夠徹底不用關心,用本身PushSDK那套就能夠。若是沒有自家PushSDK,那就須要選擇一個SDK進行透傳處理,固然,仍要接入第三方離線推送能力。不過即便如此,各家ROM的接入規則也個不相同,好比小米有個奇葩的權限叫:「後臺彈出界面權限 」,若是後端服務Push姿式不對,可能會引入奇葩問題:好比,手機能收到PUSH,可是拉不起界面,坑爹。

簡單看下各ROM計入注意事項,只看離線能力,不考慮透傳:

小米

關於MIPUSH的接入,直接看官方文檔便可,沒太多問題,須要注意的是,小米有個奇葩的權限設置:後臺彈出界面權限 ,該權限默認是關閉,這個選項可能會影響推送通知的點擊行爲,小米有兩大類點擊行爲:

徹底自定義點擊行爲

在這種行爲下,開發者能夠攔截通知點擊事件,自定義如何處理後續事件,點擊後,MiPushMessage經過PushMessageReceiver繼承類的onNotificationMessageClicked方法傳到APP進程,開發者可自行處理,若是想要啓動界面,只須要在其中調用context.startActivity方法便可,可是,這種自定義的行爲會受到後臺彈出界面權限的影響,尤爲是高版本的MIUI ROM中。

你會發現,在這些手機上,此方式壓根無法拉起APP,除非經過先啓動一個Service,而後在Service中拉起,很是像小米的一個BUG,而且,即便經過此下策能拉起,你會發現,拉起速度很是慢,多是過多AMS交互通訊致使的,因此這種策略能夠斃了。

預約義點擊行爲

預約義點擊行爲不用用戶在onNotificationMessageClicked中處理,系統會直接拉起目標頁面,小米支持三種預約義點擊行爲:

  • (1) 打開當前的Launcher Activity
  • (2) 打開當前app內的任意一個Activity
  • (3) 打開網頁。

APP通常會採用第二種行爲,打開APP任意一個Activity,其實最終會選擇一個DeepLink Activity,由其路由到其餘界面。服務端調用Message.Builder類的extra(String key, String value)方法,將key設置爲Constants.EXTRA_PARAM_NOTIFY_EFFECT,value設置爲Constants.NOTIFY_ACTIVITY即可以達到該效果,用戶點擊了客戶端彈出的通知消息後,封裝消息的MiPushMessage對象經過Intent傳到客戶端,客戶端可在Activity中解析,並自行處理後續流程。離線推送狀況下,推送服務端核心字段以下:

採用離線非透傳消息,並利用extra自定義Click行爲,最後推送給小米的消息格式簡化以下:

{
	title=通知標題, 
	description=通知內容, 
	restrictedPackageNames=[com.test.example], 
	notifyType=1, 
	notifyId=1249808047, 
	<!--打開任意Activity配置-->
	extra.intent_uri=yanxuan://re?opOrderId=crm_a1d05c1d3d1743e192a08b461a376785_20200715,
	extra.notify_effect=2
}
複製代碼

extra.intent_uri的值就是APP端定義的私有scheme,點擊通知會直接拉起相應的DeepLink Activity,從而喚起應用,至於DeepLink Activity最終路由到哪一個界面,能夠從extra.intent_uri中解析出來。對於上文層說過的click事件不易統計的問題,能夠經過在scheme家參數的方式解決,以下:

extra.intent_uri= yanxuan://re?opOrderId=0200715, 
複製代碼

轉爲

extra.intent_uri= yanxuan://re?opOrderId=0200715&platform=xiaomi 
複製代碼

以後在路由Activity中能夠解析出platform參數,從而標記click事件及來源平臺。預約義行爲系統會幫咱們處理好喚起,在APP中,不須要在onNotificationMessageClicked再次響應click事件了,避免重複處理。後面其他各方SDK的能力基本都跟小米相似,大同小異,沒多少花樣。

華爲

流程同小米相似,按文檔便可,預約義行爲有以下四種:

  • 1:用戶定義Uri,打開目標界面
  • 2:點擊後打開特定網頁
  • 3:點擊後打開應用
  • 4:點擊後打開富媒體信息

通常選擇自定義Uri行爲,全部數據經過intent uri傳輸給APP,依舊是私有scheme的DeepLink實現方式。對應參數意義以下:

基本上,選擇type=1 同 intent uri配合,uri生成格式以下:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("pushscheme://com.huawei.codelabpush/deeplink?name=abc&age=180"));
String intentUri = intent.toUri(Intent.URI_INTENT_SCHEME);
複製代碼

最終經過API發送給華爲push平臺數據格式簡化以下:

"msg":{
    "action":{
        "param":{
            "intent":"intent://member?url=http%3A%2F%2Fm.you.163.com%2Fmembership%2Findex&_yanxuan_hwpush=1&_mid=a397314518947995648#Intent;scheme=yanxuan;launchFlags=0x4000000;end"
        },
        "type":1
    },
    "body":{
        "title":"huawei免郵券禮包",
        "content":"快來領取你的每個月專屬免運費券,當即領取>>"
    }
}
複製代碼

同小米相似,若是須要添加額外參數,放到scheme中,再也不敖述。

魅族

接入相似,支持四種預約義行爲:

  • 打開應用主頁
  • 打開應用內頁面
  • 打開URI頁面
  • 客戶端自定義

一樣選擇預約義Uri頁面,具體參數以下

最終發送數據格式簡化以下:

{
	 noticeBarType = 0,
	 title = 'meizu明天以後⏰恢復原價', 
	 content = '店慶爆款返場!乳膠牀墊直降500,拉桿箱僅7折!😱每滿150減25消費券全品類通用,最後1天>>',
	 clickType = 2, 
	 url = 'yanxuan://yxwebview?url=https%3A%2F%2Fact.you.163.com%2Fact%2Fpub%2FDisjY2u1n9p4SB3.html%3Fanchor%3DSeen3xcj%26opOrderId%3Dcrm_task_20200414160053263_1'
 }
複製代碼

clickType = 2 配合Uri scheme來實現,預約義拉起對應界面,若是須要添加額外參數,同上。

oppo

接入相似,oppo沒法感知click事件,支持五種預約義行爲(有冗餘):

  • 0,啓動應用;
  • 1,打開應用內頁(activity的intent action)
  • 2,打開網頁;
  • 4,打開應用內頁(利用activity全名)
  • 5, Intent scheme URL

處理相似,選click_action_type選擇5,經過私有scheme拉起APP,具體數據格式以下

{
    "notification":{
        "app_message_id":"a467798011733344256",
        "channel_id":"NotificationChannel",
        "click_action_url":"yanxuan://yxwebview?url=https%3A%2F%2Fact.you.163.com%2Fact%2Fpub%2FDisjY2u1n9p4SB3.html%3Fanchor%3DSeen3xcj%26opOrderId%3Dcrm_task_20200414160053263_1",
        "click_action_type":5,
        "content":"明天以後恢復原價",
        "title":"明天以後恢復原價"
    },
    "target_type":2,
    "target_value":"CN_04f112241e183f6309611df2a95d6237"
}
複製代碼

click_action_type= 5 配合 scheme拉起APP,,若是須要添加額外參數,同上。

vivo

vivo跟oppo很相似,不過它也能夠收到click事件(並沒什麼卵用),所以支持徹底自定義(然而不用),支持五種Click行爲

  • 1:打開APP首頁
  • 2:打開連接
  • 3:自定義
  • 4:打開app內指定頁面

一樣,爲了防止禁止後臺啓動,不採用自定義的方式,而直接打開打開app內指定頁面, "skipType":4,

{
    "classification":1,
    "content":"adssdsr345436",
    "notifyType":1,
    "pushMode":1,
    "regId":"15905547110541891320627",
    "requestId":"a467798011733344256",
    "skipContent":"yanxuan://yxwebview?url=https%3A%2F%2Fact.you.163.com%2Fact%2Fpub%2FDisjY2u1n9p4SB3.html%3Fanchor%3DSeen3xcj%26opOrderId%3Dcrm_task_20200414160053263_1",
    "skipType":4,
    "title":"adssdsr345436"
}
複製代碼

skipType:4配合 scheme拉起APP,,若是須要添加額外參數,同上。

各ROM接入事項小結

以上是幾種離線推送的接入方式,總體總結就是:

  • 儘可能選擇預約義Uri scheme方式,不要採用自定義的方式
  • 能夠在scheme中填加參數,統一鑑別click事件
  • 在預約義的方式下,不要在click回調中重複處理事件
  • 若是隻要離線推送功能,不必處理透傳配置(好比什麼Receiver Service之類的配置)

總結

  • 不得不接入第三方SDK是爲了離線推送
  • 各家離線推送大同小異,爲了統一建議統一採用預約義Uri方式,配合私有scheme拉起APP
  • 額外追蹤參數能夠經過添加scheme字段解決
  • 不一樣ROM可能有本身的額外限制,好比小米,儘可能避免受其限制

最後,Android的推送困境是個悲劇...

相關文章
相關標籤/搜索