电竞比分网-中国电竞赛事及体育赛事平台

分享

不會(huì)吧,這也行?iOS 后臺(tái)鎖屏監(jiān)聽搖一搖

 泰榮林黑皮 2021-11-06
轉(zhuǎn)自:Dast1Woop

https:///post/6881420727371694093

背景介紹

一般情況下,出于省電、權(quán)限、合理性等因素考慮,給人的感覺是很多奇怪的需求安卓可以實(shí)現(xiàn),但是iOS就無法實(shí)現(xiàn)!今天要介紹的需求也有這種感覺,就是“當(dāng) APP 處于后臺(tái)或鎖屏狀態(tài)時(shí),依舊可以監(jiān)聽到搖一搖,進(jìn)而觸發(fā)某些功能,比如:語音播報(bào)”。

在產(chǎn)品經(jīng)理提出此需求的一瞬間,仿佛周邊的空氣都凝固了,我也猶如五雷轟頂,愣在原地?zé)o法動(dòng)彈。不由心想:“蘋果爸爸怎么可能允許開發(fā)者實(shí)現(xiàn)這種功能!這得多費(fèi)電?。∫撬?APP 都這么做了,那還了得!” 與此同時(shí),之前網(wǎng)上瘋傳、遠(yuǎn)近聞名的的需求--“做一個(gè)會(huì)根據(jù)手機(jī)殼顏色而改變主題顏色的APP”,清晰地浮現(xiàn)在腦海中,頓時(shí)一萬只xx??從心中奔騰而過。此時(shí),產(chǎn)品經(jīng)理解釋到,這是咱們好多視力障礙用戶提的需求,他們經(jīng)常鎖屏或把 APP 退到后臺(tái),且因?yàn)橐暳Σ患言?,?dǎo)致重新找到 APP 并切到前臺(tái)的操作很是麻煩,所以十分希望我們能實(shí)現(xiàn)這個(gè)功能。

在短暫的心理活動(dòng)后,秉著“客戶第一,產(chǎn)品????”的原則,于是回復(fù)說:“這功能太少見了,我先在網(wǎng)上看看吧,要是有其他 APP 有類似的功能,麻煩跟我說我參考一下。”然后,就祭出了程序員利器--Google,輸入“iOS 后臺(tái) 搖一搖”,只搜索出來的一個(gè)思路:利用 CoreMotion 框架,監(jiān)聽加速計(jì)原始數(shù)據(jù),然后在 APP 退到后臺(tái)后,可以實(shí)現(xiàn)監(jiān)聽搖一搖的效果。然而,并沒有完整的代碼或 demo 。頓時(shí),Talk is cheap, show me the code!這句經(jīng)典臺(tái)詞突然地出現(xiàn)在腦海中!也看到有人評(píng)論說 CoreMotion 的確可以實(shí)現(xiàn)跟系統(tǒng)搖一搖類似的效果,但是退到后臺(tái)或鎖屏后,沒辦法監(jiān)聽到搖一搖事件。

看到這條評(píng)論時(shí),我不禁開始懷疑此功能是否真的可以被實(shí)現(xiàn)。

玩歸玩,鬧歸鬧,開始 code,不開玩笑。

接下來,開始自己的探索之旅。

本文 demo 鏈接為 OCDailyTests/BackgroundShakeTest https://github.com/Dast1Woop/OCDailyTests.git,可自行下載,方便運(yùn)行和驗(yàn)證。

探索過程

其他 APP 有沒有類似功能

經(jīng)過一番 Google,終于找到一款 APP 有類似功能::酷狗音樂 APP,對(duì),就是那個(gè)在 PC 端一打開就會(huì)大喊 Hello KuGou!的音樂軟件對(duì)應(yīng)的 APP,萬萬沒想到,手機(jī) APP 也是這樣,一句Hello KuGou!把我嚇一跳。按如下步驟,在設(shè)置里打開此功能后,后臺(tái)或鎖屏?xí)r,搖一搖手機(jī),可實(shí)現(xiàn)切歌的效果。

圖片

圖片

圖片

既然的確有 APP 實(shí)現(xiàn)了此功能,那就踏踏實(shí)實(shí)地探索它可能是怎么實(shí)現(xiàn)的吧。

系統(tǒng)提供的搖一搖回調(diào)能否滿足

系統(tǒng)搖一搖回調(diào)方法:

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event{
NSLog(@'%s', __FUNCTION__);
}

經(jīng)測(cè)試,此方法只有在 APP 處于前臺(tái)時(shí),才會(huì)被回調(diào)。APP 處于后臺(tái)或鎖屏?xí)r,此方法不會(huì)回調(diào)。故初步判定此方法不能滿足需求。

**其他方法能否實(shí)現(xiàn) **

此時(shí),還是先根據(jù)網(wǎng)上各路大神提供的思路進(jìn)行嘗試,即利用 CoreMotion 框架,監(jiān)聽加速計(jì)原始數(shù)據(jù),然后在 APP 退到后臺(tái)后,實(shí)現(xiàn)監(jiān)聽搖一搖的效果。

好,我們先利用 CoreMotion 框架,監(jiān)聽加速計(jì)原始數(shù)據(jù),實(shí)現(xiàn)類似系統(tǒng)搖一搖回調(diào)的效果。

利用 CoreMotion 框架,監(jiān)聽加速計(jì)原始數(shù)據(jù)

通過加速計(jì)監(jiān)聽搖一搖

因加速計(jì)回調(diào)比較頻繁,因此比較占用資源,故把此功能設(shè)計(jì)為單例。

  • 快速實(shí)現(xiàn)單例效果

//具體實(shí)現(xiàn)詳見 demo 中文件
#import 'HMSingleton.h'

@interface MYAccelerometerTool : NSObject
HMSingleton_h(MYAccelerometerTool);
@end

@implementation MYAccelerometerTool
HMSingleton_m(MYAccelerometerTool);
@end
  • 聲明和懶加載運(yùn)動(dòng)管理員屬性

@property(nonatomic, strong) CMMotionManager *gMotionMnger;

- (CMMotionManager *)gMotionMnger{
if (nil == _gMotionMnger) {
CMMotionManager *lMnger = [[CMMotionManager alloc] init];
lMnger.accelerometerUpdateInterval = 0.1;
[lMnger startAccelerometerUpdates];
_gMotionMnger = lMnger;
}
return _gMotionMnger;
}

聲明和實(shí)現(xiàn)時(shí)間戳屬性,用于實(shí)現(xiàn)節(jié)流效果(為防止頻繁回調(diào),每次檢測(cè)成功后,停止搖動(dòng) 1s 后才繼續(xù)響應(yīng)下次搖一搖。)

@property(nonatomic, strong) NSDate *gDateLastShakeSuc;
- (NSDate *)gDateLastShakeSuc{
if (nil == _gDateLastShakeSuc) {
_gDateLastShakeSuc = [NSDate distantPast];
}
return _gDateLastShakeSuc;
}
  • 開始監(jiān)聽搖一搖動(dòng)作

- (BOOL)startMonitorShake{
if (NO == self.gMotionMnger.isAccelerometerAvailable) {
return NO;
}

//監(jiān)聽中,直接返回YES
if (self.gMotionMnger.isAccelerometerActive) {
return YES;
}

[self.gMotionMnger startAccelerometerUpdatesToQueue:[NSOperationQueue new] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {

CMAcceleration acceleration = accelerometerData.acceleration;

//綜合x、y兩個(gè)方向的加速度(z方向速度無意義,用的話,走路上下抖手機(jī)時(shí)會(huì)誤觸發(fā),系統(tǒng)搖一搖也不會(huì)被z軸加速度觸發(fā))
//當(dāng)綜合加速度大于2.3時(shí),就激活效果(數(shù)據(jù)越小,用戶搖動(dòng)的動(dòng)作就越小,越容易激活)
double accelerameter = sqrt( pow( acceleration.x , 2 ) + pow( acceleration.y , 2 ));

if (accelerameter > 2.3) {

//節(jié)流效果:距離上次搖一搖成功事件,間隔時(shí)間小于1s時(shí),認(rèn)為無效
NSDate *lCrtDate = [NSDate date];
if ([lCrtDate timeIntervalSinceDate:self.gDateLastShakeSuc] < 1) {
self.gDateLastShakeSuc = lCrtDate;
return ;
}

self.gDateLastShakeSuc = lCrtDate;
[[NSNotificationCenter defaultCenter] postNotificationName:KNTFY_SHAKE_SUCCESS object:nil];
}
}];

return YES;
}
  • 為了代碼的對(duì)稱美和可能的相關(guān)業(yè)務(wù),實(shí)現(xiàn)停止監(jiān)聽搖一搖方法

- (void)stopMonitorShake{
[self.gMotionMnger stopAccelerometerUpdates];
self.gMotionMnger = nil;
self.gDateLastShakeSuc = nil;
}

控制器相關(guān)邏輯和代碼

  • 開始監(jiān)聽搖一搖

BOOL lRes = [[MYAccelerometerTool sharedMYAccelerometerTool] startMonitorShake];
NSLog(@'lRes:%d', lRes);
NSAssert(lRes, @'開始監(jiān)聽搖一搖失敗');
  • 監(jiān)聽搖一搖成功的通知

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nmShakeSuccess:) name:KNTFY_SHAKE_SUCCESS object:nil];

//在搖一搖的同時(shí),通過觀察此方法是否有l(wèi)og,可以判斷是否有監(jiān)聽到。
- (void)nmShakeSuccess:(NSNotification *)ntfy{
NSLog(@'%s', __FUNCTION__);
}
  • dealloc方法中取消監(jiān)聽

- (void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

運(yùn)行 demo 工程,測(cè)試可知,通過上述方法,的確可以在 APP 處于前臺(tái)時(shí),實(shí)現(xiàn)監(jiān)聽搖一搖動(dòng)作的效果。可是,當(dāng)把 APP 退到后臺(tái)或鎖屏?xí)r,nmShakeSuccess 方法不再有 log,即:APP 處于后臺(tái)時(shí),通過監(jiān)聽加速計(jì)的方法,默認(rèn)也無法在 APP 處于后臺(tái)或鎖屏?xí)r實(shí)現(xiàn)監(jiān)聽效果。這也印證了上文提到的那個(gè)評(píng)論者的疑問。

可是 Hello KuGou!明明實(shí)現(xiàn)了后臺(tái)或鎖屏?xí)r搖一搖的效果??!難道是需要額外的配置?聯(lián)想 iOS 處于后臺(tái)時(shí),默認(rèn)會(huì)把 APP 的服務(wù)給掛起(suspended),只有當(dāng) APP 通過某種方式(后臺(tái)定位/播放音樂/藍(lán)牙掃描等)具有后臺(tái)運(yùn)行權(quán)限時(shí),才可以一直?;睢?刹孪?,也許賦予 APP 具有后臺(tái)運(yùn)行的權(quán)限后,就可以實(shí)現(xiàn)想要的功能了。于是,開始進(jìn)行驗(yàn)證如下。

APP 申請(qǐng)后臺(tái)運(yùn)行權(quán)限后,能否監(jiān)聽到搖一搖

因?yàn)楣ぷ髦泻芏?APP 具有后臺(tái)定位權(quán)限和相關(guān)功能,所以本文通過為 APP 申請(qǐng)后臺(tái)定位權(quán)限來驗(yàn)證。
APP 申請(qǐng)后臺(tái)定位權(quán)限

  • plist 文件中增加”定位請(qǐng)求描述信息“

<key>NSLocationAlwaysUsageDescription</key>
<string>我們需要根據(jù)您的定位提供周邊搜索和導(dǎo)航服務(wù)</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>我們需要根據(jù)您的定位提供周邊搜索和導(dǎo)航服務(wù)</string>

增加”后臺(tái)定位權(quán)限“

<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
  • 聲明定位管理員屬性

@property(nonatomic, strong) CLLocationManager *gMnger;
  • 懶加載定位管理員,請(qǐng)求定位權(quán)限、允許后臺(tái)位置更新

- (CLLocationManager *)gMnger{
if (nil == _gMnger) {
_gMnger = [[CLLocationManager alloc] init];
_gMnger.delegate = self;
_gMnger.allowsBackgroundLocationUpdates = YES;
[_gMnger requestWhenInUseAuthorization];
}
return _gMnger;
}
  • 代理 3 步走(用于驗(yàn)證后臺(tái)定位是否生效)

遵守代理協(xié)議

@interface ViewController ()<CLLocationManagerDelegate>

指定代理對(duì)象

_gMnger.delegate = self;

實(shí)現(xiàn)代理方法

#pragma mark -  delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
NSLog(@'%s', __FUNCTION__);
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(@'%s', __FUNCTION__);
}
  • APP 后臺(tái)或鎖屏后,測(cè)試能否成功監(jiān)聽搖一搖

運(yùn)行 demo 工程,經(jīng)測(cè)試,把 APP 退到后臺(tái)或鎖屏,或即退到后臺(tái)又鎖屏,都能夠檢測(cè)到搖一搖事件。

多 APP 都實(shí)現(xiàn)此功能時(shí),搖一搖是何效果

這里用 demo APP 和酷狗音樂 APP 進(jìn)行測(cè)試。

  • 同時(shí)打開這兩個(gè) APP,其中酷狗音樂 APP 打開后臺(tái)搖一搖切歌的功能。

  • 酷狗音樂 APP 開始放歌,退到后臺(tái)。

  • demo APP 打開后,退到后臺(tái)。

  • 搖一搖,查看效果:

    • 當(dāng)搖動(dòng)的力度不是很大時(shí),demo APP 回調(diào)方法會(huì)被觸發(fā);

    • 當(dāng)搖動(dòng)的力度很大時(shí),demo APP 回調(diào)方法和酷狗 APP 切歌會(huì)同時(shí)被觸發(fā);

  • 由此可見,如果多個(gè) APP 同時(shí)實(shí)現(xiàn)了此功能時(shí),那么后臺(tái)或鎖屏搖一搖時(shí),只要滿足了某個(gè) APP 實(shí)現(xiàn)的加速計(jì)相關(guān)判定條件,就可以同時(shí)觸發(fā)多個(gè) APP 對(duì)應(yīng)的效果。

后臺(tái)定位權(quán)限 + 系統(tǒng)搖一搖,是否可行?

經(jīng)測(cè)試,還是不行。果然,系統(tǒng)搖一搖還是比較受限的,只能在前臺(tái)回調(diào)。

文章小結(jié)

想要實(shí)現(xiàn)”iOS后臺(tái)鎖屏監(jiān)聽搖一搖“功能,   

首次,必須滿足一個(gè)硬性條件:APP 具有某種后臺(tái)運(yùn)行的權(quán)限。

其次,技術(shù)實(shí)現(xiàn)上必須使用CoreMotion框架,通過監(jiān)聽加速計(jì)回調(diào)自己實(shí)現(xiàn)對(duì)搖一搖事件的監(jiān)聽判定。

最后,可通過增加時(shí)間屬性,實(shí)現(xiàn)對(duì)搖一搖事件監(jiān)聽時(shí)的節(jié)流效果,防止持續(xù)搖動(dòng)時(shí),太過頻繁的事件回調(diào)。

此外,多 APP 都實(shí)現(xiàn)此功能時(shí),搖一搖的效果是:只要搖動(dòng)力度很大,加速計(jì)數(shù)據(jù)滿足 APP 實(shí)現(xiàn)的搖一搖判定條件,就可以同時(shí)觸發(fā)多個(gè) APP 各自對(duì)應(yīng)的效果。

因此,如果不是 APP 特別需要此功能,盡量不要這樣實(shí)現(xiàn),畢竟,比較占用系統(tǒng)資源,而且太多 APP 同時(shí)實(shí)現(xiàn)時(shí),可能會(huì)出現(xiàn)效果上的相互干擾。不過,如果合理利用此功能,卻可以為特殊用戶群體提供極大的便利!

通過探索,滿足了視力障礙用戶的迫切需求,還是蠻有成就感的!

偷偷的告訴大家,寫到這里時(shí),產(chǎn)品經(jīng)理還沒告訴我他所知道的哪個(gè) APP 實(shí)現(xiàn)了這個(gè)功能,可能他太忙,給忘記了吧......

-End-

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多