iOS 后臺穩(wěn)定定位方案(超級省電)

在開發(fā)工程師端的過程中辞色,有一個需求是每隔5分鐘就要定位一次工程師的位置,一旦有訂單來了浮定,就根據(jù)用戶的坐標分配最近的工程師相满。但是這個需求最初的方案是,讓APP長駐后臺桦卒,這個又造成耗電嚴重的問題立美。后來發(fā)現(xiàn)蘋果有個解決長連接的方案,就是PushKit! 方灾。

目前該方法已不可用建蹄。

一.定位服務(wù)

目前定位服務(wù)使用的是百度地圖的定位。


1.根據(jù)官方的說明集成百度地圖

2.除了正常的設(shè)置APP的定位權(quán)限外裕偿,現(xiàn)在有個問題洞慎,那就是用戶在選擇訪問位置權(quán)限的時候有3個參數(shù),'永不','使用應(yīng)用期間','始終'嘿棘。如果用戶選中了非始終的其他兩個選項劲腿,那么后臺就無法定位。

解決方案:
-(void) startLocationService{
    
    if ([CLLocationManager locationServicesEnabled] && ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways ||[CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)) {
        
    }else if ([CLLocationManager locationServicesEnabled] && ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse)){//僅在使用APP時定位
        
        UIAlertController *TipAlert = [UIAlertController alertControllerWithTitle:@"警告" message:@"當前位置權(quán)限為\"使用應(yīng)用期間\" \n請修改為\"始終\"" preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *goOnAction = [UIAlertAction actionWithTitle:@"設(shè)置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            NSURL * url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
            if ([[UIApplication sharedApplication] canOpenURL:url]) {
                if (iOS10) {
                    #ifdef NSFoundationVersionNumber_iOS_10
                    [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
                    #endif
                } else {
                    [[UIApplication sharedApplication] openURL:url];
                }
            }
        }];
        
        [TipAlert addAction:goOnAction];
        [self.mainViewController presentViewController:TipAlert animated:YES completion:^{
            
        }];
        
    }else{
        //定位不能用
        NSLog(@"定位不能用");
        
        UIAlertController *TipAlert = [UIAlertController alertControllerWithTitle:@"警告" message:@"未獲取位置權(quán)限 \n請設(shè)置位置權(quán)限為 \"始終\"" preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *goOnAction = [UIAlertAction actionWithTitle:@"設(shè)置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            NSURL * url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
            if ([[UIApplication sharedApplication] canOpenURL:url]) {
                if (iOS10) {
                    #ifdef NSFoundationVersionNumber_iOS_10
                    [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
                    #endif
                } else {
                    [[UIApplication sharedApplication] openURL:url];
                }
            }
        }];
        
        [TipAlert addAction:goOnAction];
        [self.mainViewController presentViewController:TipAlert animated:YES completion:^{
            
        }];
    }
}

這個方法是檢查定位權(quán)限的方法鸟妙,除了在應(yīng)該檢查權(quán)限的地方檢查焦人,在用戶從設(shè)置界面回來的時候挥吵,也應(yīng)該再檢查一遍!

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    
    //用戶可能去設(shè)置定位了花椭,現(xiàn)在回來檢查一下
    [self startLocationService];
}

這樣就能保證至少權(quán)限是正常使用的忽匈,在info文件設(shè)置權(quán)限可別忘了-->看這里, 因為已經(jīng)設(shè)置到后臺定位了,這個必須要設(shè)置矿辽!

定位的代碼現(xiàn)在這里脉幢,下面說一下PushKit!

二.PushKit

PushKit是iOS8之后,蘋果引入的新push方式嗦锐,有別于普通的APNs,它不會彈出通知沪曙,而是悄悄的告訴我們的app有推送過來奕污,讓app做出相應(yīng)的處理。我目前的測試環(huán)境最低支持到iOS10液走,不太清楚iOS8和iOS9的穩(wěn)定性碳默,有心的朋友測試了可以給我留言,哈哈哈缘眶。嘱根。。

蘋果開發(fā)PushKit原本是給VoIP應(yīng)用使用的巷懈,所以沒有充分理由该抒,非VoIP想要上AppStore,難于上青天顶燕!現(xiàn)在更好了凑保,VoIP的體驗直逼三大運營商的體驗,所以秉承社會主義涌攻,PushKit即便在VoIP的應(yīng)用上使用欧引,同樣不能上線到大陸的AppStore!


1.制作證書(我去盜的圖 <--臭不要臉!)


第一步.png
第二步.png

后面的步驟恳谎,和制作其他證書的步驟都是一樣的芝此!

把證書下載下來后,雙擊安裝到電腦因痛,我后面要貼java代碼婚苹,所以需要導(dǎo)出p12格式的證書,默認導(dǎo)出的就是p12證書鸵膏。如果要測試租副,推薦使用 Pusher for Mac

界面樣式.png

2.開始代碼時間较性!
(1)導(dǎo)入push kit框架#import <PushKit/PushKit.h>
(2)別忘了導(dǎo)包用僧,之前忘了導(dǎo)结胀,一直報錯!


導(dǎo)包.png

(3)- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions ;
調(diào)用下面的方法設(shè)置pushKit

#pragma mark - creatVoIP
- (void)creatVoIP{
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    center.delegate = self;
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {

    }];

    [UIApplication.sharedApplication registerForRemoteNotifications];

    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    // Create a push registry object
    PKPushRegistry * voipRegistry = [[PKPushRegistry alloc] initWithQueue: mainQueue];
    // Set the registry's delegate to self
    voipRegistry.delegate = self;
    // Set the push type to VoIP
    voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}

(4)協(xié)議方法 PKPushRegistryDelegate

PushKit的推送token與APNs是不一樣的责循!糟港,下面的協(xié)議方法可以獲取到!

#pragma mark - PKPushRegistryDelegate
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)pushCredentials forType:(PKPushType)type{
    
    NSString *str = [NSString stringWithFormat:@"%@",pushCredentials.token];
    NSString *tokenStr = [[[str stringByReplacingOccurrencesOfString:@"<" withString:@""]
                           stringByReplacingOccurrencesOfString:@">" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"tokenStr獲取到的就是PushKit的token");
    NSLog(@"實際生產(chǎn)中院仿,把這個token傳給后端的同學秸抚,我們測試可以拷貝出來,放到pusher里面測試");
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void(^)(void))completion{
    //收到pushKit通知
    [_locationManager requestLocationWithReGeocode:YES withNetworkState:YES completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) {

        if (location) {//得到定位信息歹垫,下面的代碼純粹是為了測試的效果剥汤,實際應(yīng)用中,把位置信息傳給后臺就可以了

            if (location.location) {
                NSLog(@"LOC = %@",location.location);
            }
            if (location.rgcData) {
                NSLog(@"rgc = %@",[location.rgcData description]);
            }

            NSString *Str = [NSString stringWithFormat:@"L:%@  R:%@",location.location,[location.rgcData description]];

            UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
            center.delegate = self;
            UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
            content.title = [NSString localizedUserNotificationStringForKey:@"定位信息" arguments:nil];
            content.body = [NSString localizedUserNotificationStringForKey:Str arguments:nil];
            content.sound = [UNNotificationSound defaultSound];

            UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"OXNotification" content:content trigger:nil];

            [center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
                NSLog(@"成功添加推送");
            }];
        }
    }];
}
- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type{
    NSLog(@"");
}

(5)特別說明排惨!

我在第二個協(xié)議方法里面發(fā)送了一個自定義通知吭敢,為了在殺死APP的情況下進行測試,下面的代碼是為了方便大家的測試寫的暮芭,和本文設(shè)計到的長連接沒有關(guān)系鹿驼!

1.導(dǎo)入頭文件

#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#import <UserNotifications/UserNotifications.h>
#import <UserNotificationsUI/UserNotificationsUI.h>
#endif

2.協(xié)議方法
UNUserNotificationCenterDelegate

#pragma mark - ios10才支持的通知!

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    NSLog(@"");
    completionHandler(UNNotificationPresentationOptionAlert);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{
    NSLog(@"");
}

//ios 12才支持
- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification{
    
}

java代碼:

import javapns.back.PushNotificationManager;
import javapns.back.SSLConnectionHelper;
import javapns.data.Device;
import javapns.data.PayLoad;

public class Main {
    public static void main(String[] args) throws Exception{
        try {
            // token為不包含空格和<>的字母數(shù)字組合(字母不區(qū)分大小寫)
            String deviceToken = "XXXXXXXXXX";
            PushNotificationManager pushManager = PushNotificationManager.getInstance();
            pushManager.addDevice("iphone", deviceToken);

            // 蘋果推送服務(wù)器
             /*
             開發(fā)狀態(tài)服務(wù)器地址 gateway.sandbox.push.apple.com 2195
             發(fā)布狀態(tài)服務(wù)器地址 gateway.push.apple.com 2195

             需要注意:
             Xcode打出的Debug安裝包只能選擇開發(fā)服務(wù)器,證書可以選擇開發(fā)推送證書或者發(fā)布推送證書辕宏;
             Xcode打出的AdHoc或Release安裝包只能選擇發(fā)布務(wù)器和發(fā)布推送證書畜晰;
             */
            String host= "gateway.push.apple.com";
            // 端口號
            int port = 2195;

            // 在mac系統(tǒng)下導(dǎo)出的p12證書(開發(fā)證書對應(yīng)開發(fā)環(huán)境,發(fā)布證書對應(yīng)所有環(huán)境)
            String certificatePath = "J:\\QQdir\\2\\JKX_e.p12";
            // p12證書密碼
            String certificatePassword= "12345678";
            // 初始化tcp連接
            pushManager.initializeConnection(host, port, certificatePath, certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);

            // Send Push
            Device client = pushManager.getDevice("iphone");
            // 要推送的消息
            PayLoad payLoad = new PayLoad();
            payLoad.addAlert("收到消息CALL我");
            payLoad.addBadge(1);
            payLoad.addSound("default");
            // 開始推送
            pushManager.sendNotification(client, payLoad);
            pushManager.stopConnection();
            pushManager.removeDevice("iphone");
            System.out.println ("success");
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
  }

需要用到的jar包

bcprov-jdk16-145-1.jar 
commons-io-2.0.1.jar
commons-lang-2.5.jar
javapns-jdk16-163.jar
log4j-1.2.16.jar

這個代碼和后端的同學測試通過的瑞筐,java沒寫清楚的地方凄鼻,可以看這個

如果發(fā)現(xiàn)錯誤聚假,請大家留言指出野宜,謝謝!

如果發(fā)現(xiàn)不清楚的地方魔策,請留言匈子,我會修改的!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闯袒,一起剝皮案震驚了整個濱河市虎敦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌政敢,老刑警劉巖其徙,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異喷户,居然都是意外死亡唾那,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門褪尝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闹获,“玉大人期犬,你說我怎么就攤上這事”芊蹋” “怎么了龟虎?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沙庐。 經(jīng)常有香客問我鲤妥,道長,這世上最難降的妖魔是什么拱雏? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任棉安,我火速辦了婚禮,結(jié)果婚禮上铸抑,老公的妹妹穿的比我還像新娘贡耽。我一直安慰自己,他們只是感情好羡滑,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著算芯,像睡著了一般柒昏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上熙揍,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天职祷,我揣著相機與錄音,去河邊找鬼届囚。 笑死有梆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的意系。 我是一名探鬼主播泥耀,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蛔添!你這毒婦竟也來了痰催?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤迎瞧,失蹤者是張志新(化名)和其女友劉穎夸溶,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凶硅,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡缝裁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了足绅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捷绑。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡韩脑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出胎食,到底是詐尸還是另有隱情扰才,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布厕怜,位于F島的核電站衩匣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏粥航。R本人自食惡果不足惜琅捏,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望递雀。 院中可真熱鬧柄延,春花似錦、人聲如沸缀程。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杨凑。三九已至滤奈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撩满,已是汗流浹背蜒程。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伺帘,地道東北人昭躺。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像伪嫁,于是被迫代替她去往敵國和親领炫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

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