APP語音推送

APP語音推送

標(biāo)簽(空格分隔): 極光推送 語音推送 APNS


目前主流的推送解決方案分為兩種。

  • 自己搭建推送平臺巴柿,對服務(wù)器并發(fā)處理能力、開發(fā)人員技術(shù)能力、不同網(wǎng)絡(luò)環(huán)境處理機制等要求較高杀餐,適用于資源豐富的團(tuán)隊。

  • 采用第三方公司提供的推送服務(wù)朱巨,極光推送史翘、百度云、信鴿等冀续,這一方案成本相對較低。因為瑞錢包之前采用的是極光推送洪唐,下面著重講一下極光推送對語音推送的實現(xiàn)方式钻蹬。


極光推送

對于iOS系統(tǒng),百度云、信鴿在App活躍和非活躍狀態(tài)時,都是通過APNS推送注整;極光推送在App非活躍狀態(tài)是通過APNS推送借浊,活躍狀態(tài)的情況,JPush Server會通過sdk建立長連接,直接由JPush Server發(fā)送消息到App內(nèi)臂港。
對于Android系統(tǒng)筋遭,只支持應(yīng)用內(nèi)推送响驴,Push SDK是作為Android Service 運行在后臺的透且,從而創(chuàng)建并保持長連接,保持在線的能力踏施,接收服務(wù)器Push的消息石蔗。


iOS

從上圖可以看出,JPush iOS Push 包括 2 個部分畅形,APNs 推送,與 JPush 應(yīng)用內(nèi)消息诉探。

  • 紅色部分是 APNs 推送日熬,JPush 代理開發(fā)者的應(yīng)用,向蘋果 APNs 服務(wù)器推送肾胯。由 APNs Server 推送到 iOS 設(shè)備上竖席。
  • 藍(lán)色部分是 JPush 應(yīng)用內(nèi)推送部分耘纱,App 啟動時,內(nèi)嵌的 JPush SDK 會開啟長連接到 JPush Server毕荐,從而 JPush Server 可以推送消息到 App 里束析。

APNS

APP進(jìn)程被殺死的情況,使用APNS推送憎亚,語音播放分兩種情況:

  • ios10.0+可以使用UNNotificationServiceExtension實現(xiàn)動態(tài)語音播放员寇。
  • ios10.0之前的系統(tǒng),只能播放固定音頻第美。

JPush應(yīng)用內(nèi)推送

APP進(jìn)程沒有被殺死的情況蝶锋,可以實現(xiàn)動態(tài)語音播放,下面是iOS關(guān)鍵實現(xiàn)代碼什往。

1.使用系統(tǒng)方法或者第三方SDK實現(xiàn)語音播放
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@"成功集成語音播報"];
 
AVSpeechSynthesizer *synth = [[AVSpeechSynthesizer alloc] init];
 
[synth speakUtterance:utterance];
2.APP在后臺語音播放扳缕,在delelgate類didFinishLaunchingWithOptions、applicationWillResignActive方法實現(xiàn)以下代碼
NSError *error = NULL;
 
AVAudioSession *session = [AVAudioSession sharedInstance];
 
[session setCategory:AVAudioSessionCategoryPlayback error:&error];
 
if(error) {
    // Do some error handling
     
}
 
[session setActive:YES error:&error];
 
if (error) {
    // Do some error handling
}
 
// 讓app支持接受遠(yuǎn)程控制事件
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
// 在AppDelegate定義屬性
@property (nonatomic, unsafe_unretained) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
- (void)applicationWillResignActive:(UIApplication *)application;
- (void)applicationWillResignActive:(UIApplication *)application {
 
    // 開啟后臺處理多媒體事件
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  
    AVAudioSession *session=[AVAudioSession sharedInstance];
  
    [session setActive:YES error:nil];
  
    // 后臺播放
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
  
    // 這樣做别威,可以在按home鍵進(jìn)入后臺后 躯舔,播放一段時間,幾分鐘吧省古。但是不能持續(xù)播放網(wǎng)絡(luò)歌曲庸毫,若需要持續(xù)播放網(wǎng)絡(luò)歌曲,還需要申請后臺任務(wù)id衫樊,具體做法是:
    _backgroundTaskIdentifier=[AppDelegate backgroundPlayerID:_backgroundTaskIdentifier];
    // 其中的_bgTaskId是后臺任務(wù)UIBackgroundTaskIdentifier _bgTaskId;
}

//實現(xiàn)一下backgroundPlayerID:這個方法:
+(UIBackgroundTaskIdentifier)backgroundPlayerID:(UIBackgroundTaskIdentifier)backTaskId{
    //設(shè)置并激活音頻會話類別
    AVAudioSession *session=[AVAudioSession sharedInstance];
  
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
  
    [session setActive:YES error:nil];
  
    //允許應(yīng)用程序接收遠(yuǎn)程控制
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  
    //設(shè)置后臺任務(wù)ID
    UIBackgroundTaskIdentifier newTaskId=UIBackgroundTaskInvalid;
  
    newTaskId=[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
  
    if(newTaskId!=UIBackgroundTaskInvalid&&backTaskId!=UIBackgroundTaskInvalid){
        [[UIApplication sharedApplication] endBackgroundTask:backTaskId];
    }
    return newTaskId;
  }

Anroid

JPush Android SDK 是作為 Android Service運行在后臺的飒赃,從而創(chuàng)建并保持長連接,保持App在線的能力科侈。
當(dāng)開發(fā)者想要及時地推送消息到達(dá) App 時载佳,只需要調(diào)用 JPush API 推送,或者使用其他方便的智能推送工具臀栈。
APP被完全殺死的情況下蔫慧,則不會受到消息,Android GCM不在國內(nèi)開放权薯。

相關(guān)代碼參考: JPush官方Github


搭建推送服務(wù)

  • 應(yīng)用外iOS采用Apple官方APNS推送姑躲,Android不支持應(yīng)用外推送;
  • 應(yīng)用內(nèi)Android自定義Android Service和Server實現(xiàn)長連接盟蚣,實時收到通知黍析,App殺掉的情況則收不到通知。iOS通過應(yīng)用內(nèi)和Server建立長連接屎开,實時接收通知阐枣。

自建推送服務(wù)要對DeviceToken做維護(hù),涉及到消息分類、消息分發(fā)蔼两、消息重發(fā)等甩鳄,長連接的穩(wěn)定性、心跳機制等技術(shù)點额划,相關(guān)優(yōu)缺點如下:

  • 優(yōu)點:在APP和Server建立Push機制妙啃,不局限于推送場景、可擴(kuò)展到其它服務(wù)器主動Push的業(yè)務(wù)場景俊戳,不受第三方SDK版本升級引起的BUG影響揖赴,自由度高、擴(kuò)展性強品抽。
  • 缺點:需要投入比較大的人力物力储笑,對技術(shù)人員架構(gòu)能力、服務(wù)器的并發(fā)處理能力圆恤、不同網(wǎng)絡(luò)環(huán)境處理機制突倍、穩(wěn)定性維護(hù)等方面要求較高。

應(yīng)用外推送

應(yīng)用外推送目前只適用于iOS系統(tǒng)盆昙,采用官方提供的APNS羽历;Android系統(tǒng)由于GCM服務(wù)在國內(nèi)不開放,所以Android應(yīng)用在完全被殺死的情況下淡喜,接收不到通知秕磷。

APNS

  1. Device連接APNs服務(wù)器并攜帶設(shè)備序列號;
  2. 連接成功炼团,APNs經(jīng)過打包和處理產(chǎn)生device_token并返回給注冊的Device澎嚣;
  3. Device攜帶獲取的device_token向我們自己的應(yīng)用服務(wù)器注冊;
  4. 完成需要被推送的Device在APNs服務(wù)器和我們自己的應(yīng)用服務(wù)器注冊瘟芝。

推送的過程經(jīng)過如下步驟:

  1. 首先易桃,安裝了具有推送功能的應(yīng)用,我們的設(shè)備在有網(wǎng)絡(luò)的情況下會連接蘋果推送服務(wù)器锌俱,連接過程中晤郑,APNS會驗證device_token,連接成功后維持一個長連接贸宏;
  2. Provider(我們自己的服務(wù)器)收到需要被推送的消息并結(jié)合被推送設(shè)備的device_token一起打包發(fā)送給APNS服務(wù)器造寝;
  3. APNS服務(wù)器將推送信息推送給指定device_token的設(shè)備;
  4. 設(shè)備收到推送消息后通知我們的應(yīng)用程序并顯示和提示用戶(聲音吭练、彈出框)诫龙。

我們需要對圖1中1、3线脚、4點赐稽,圖2中的2叫榕、4點做相應(yīng)開發(fā)浑侥。


應(yīng)用內(nèi)推送

應(yīng)用內(nèi)推送的幾種方式:

  1. 客戶端不斷的查詢服務(wù)器姊舵,檢索新內(nèi)容,稱為pull或者輪詢寓落;
  2. 客戶端和服務(wù)器之間維持一個TCP/IP長連接括丁,服務(wù)器向客戶端push。

實時性要求比較高的應(yīng)用場景伶选,目前都采用的第二種方式進(jìn)行推送史飞,iOS和Android系統(tǒng)層面的推送APNS、GCM實際也是用的第二種方式仰税,手機設(shè)備提供一個系統(tǒng)服務(wù)和官方服務(wù)器進(jìn)行長連接构资。

協(xié)議

目前主流的即時通訊協(xié)議有XMPP、MQTT陨簇,推送服務(wù)偏向采用更輕量的MQTT協(xié)議吐绵,下面是兩種協(xié)議的區(qū)別:

  1. XMPP是基于可擴(kuò)展標(biāo)記語言(XML)的協(xié)議,協(xié)議成熟河绽、強大己单,多應(yīng)用于聊天軟件中,缺點是XML冗余較高耙饰、費流量纹笼、費電,用在推送上過于復(fù)雜苟跪。
  2. MQTT是基于“發(fā)布/訂閱”模式的消息傳輸協(xié)議廷痘,相對輕量,數(shù)據(jù)量小件已,適用于移動網(wǎng)絡(luò)笋额。

維護(hù)長連接需要心跳機制,客戶端和服務(wù)器在建立長連接之后拨齐,每隔一段時間鳞陨,客戶端會發(fā)一個心跳給服務(wù)器,服務(wù)器給客戶端一個心跳應(yīng)答瞻惋,這樣就形成客戶端服務(wù)器的一次完整的握手厦滤,這個握手是讓雙方都知道他們之間的連接是沒有斷開,客戶端是在線的歼狼。如果超過一個時間的閾值掏导,客戶端沒有收到服務(wù)器的應(yīng)答,或者服務(wù)器沒有收到客戶端的心跳羽峰,那么對客戶端來說則斷開與服務(wù)器的連接重新建立一個連接趟咆,對服務(wù)器來說只要斷開這個連接即可添瓷。

iOS MQTT代碼示例(iOS github地址Android github地址):

1. 使用Cocoapods導(dǎo)入MQTT
platform :ios, "7.0"

pod "MQTTClient"
pod 'MQTTClient/Websocket'
pod 'SocketRocket'

// 導(dǎo)入頭文件
#import <MQTTClient/MQTTClient.h>
2. 建立連接
// 創(chuàng)建一個傳輸對象
MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];
// IP
transport.host = TFHOST;
//  端口
transport.port = TFPORT;
// 會話
MQTTSession *session = [[MQTTSession alloc] init];
self.session = session;
session.transport = transport;
session.delegate = self;
// 設(shè)置終端ID(可以根據(jù)后臺的詳細(xì)詳情進(jìn)行設(shè)置)
session.clientId = uid;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 會話鏈接并設(shè)置超時時間
    [session connectAndWaitTimeout:30];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        // 訂閱主題, qosLevel是一個枚舉值,指的是消息的發(fā)布質(zhì)量
        // 注意:訂閱主題不能放到子線程進(jìn)行,否則block不會回調(diào)
        [session subscribeToTopic:topic atLevel:MQTTQosLevelAtMostOnce subscribeHandler:^(NSError *error, NSArray<NSNumber *> *gQoss) {
            if (error) {
                TFLog(@"連接失敗 = %@", error.localizedDescription);
            }else{
                TFLog(@"鏈接成功 = %@", gQoss);
            }
        }];
    });
});
3. 接收消息
- (void)newMessage:(MQTTSession *)session
    data:(NSData *)data
    onTopic:(NSString *)topic
    qos:(MQTTQosLevel)qos
    retained:(BOOL)retained
    mid:(unsigned int)mid {
    // this is one of the delegate callbacks
}
4. 常用操作
- (void)disconnect{

    if (self.session) {
        [self.session disconnect];
    }   
}

- (void)close{
    if (self.session) {
        [self.session close];
    }

}

-  (void)closeWithDisconnect{

    if (self.session) {
        [self.session closeWithDisconnectHandler:^(NSError *error) {
            if (error) {
                TFLog(@"close error = %@", error.localizedDescription);
            }else{
                TFLog(@"close session");
            }
        }];
    }
}

- (void)publishAndWaitData:(NSData *)data{

    if (self.session) {
        [self.session publishAndWaitData:data onTopic:topic retain:NO qos:MQTTQosLevelAtMostOnce];
    }

}

- (void)publishAndWaitDic:(NSDictionary *)dic{

    NSError *error = nil;
    NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&error];
    [self publishAndWaitData:data];
}

總結(jié)

iOS應(yīng)用在被殺死和在后臺的情況值纱,iOS 10.0+的版本可以實現(xiàn)動態(tài)語音播放鳞贷,ios 10.0之前的版本只能播放固定音頻文件;應(yīng)用處于前臺活躍的情況虐唠,則都能實現(xiàn)動態(tài)語音播放搀愧。
Android應(yīng)用在后臺、前臺活躍的情況疆偿,都能實現(xiàn)動態(tài)語音播放咱筛;應(yīng)用在被殺死的情況,則不能收到通知杆故,普通的文本消息通知也不會收到迅箩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市处铛,隨后出現(xiàn)的幾起案子饲趋,更是在濱河造成了極大的恐慌,老刑警劉巖罢缸,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篙贸,死亡現(xiàn)場離奇詭異,居然都是意外死亡枫疆,警方通過查閱死者的電腦和手機爵川,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來息楔,“玉大人寝贡,你說我怎么就攤上這事≈狄溃” “怎么了圃泡?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長愿险。 經(jīng)常有香客問我颇蜡,道長,這世上最難降的妖魔是什么辆亏? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任风秤,我火速辦了婚禮,結(jié)果婚禮上扮叨,老公的妹妹穿的比我還像新娘缤弦。我一直安慰自己,他們只是感情好彻磁,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布碍沐。 她就那樣靜靜地躺著狸捅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪累提。 梳的紋絲不亂的頭發(fā)上尘喝,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音刻恭,去河邊找鬼瞧省。 笑死扯夭,一個胖子當(dāng)著我的面吹牛鳍贾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播交洗,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骑科,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了构拳?” 一聲冷哼從身側(cè)響起咆爽,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎置森,沒想到半個月后斗埂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡凫海,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年呛凶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片行贪。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡漾稀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出建瘫,到底是詐尸還是另有隱情崭捍,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布啰脚,位于F島的核電站殷蛇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏橄浓。R本人自食惡果不足惜粒梦,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贮配。 院中可真熱鬧谍倦,春花似錦、人聲如沸泪勒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叼旋,卻和暖如春仇哆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背夫植。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工讹剔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人详民。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓延欠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親沈跨。 傳聞我的和親對象是個殘疾皇子由捎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容