IOS基礎(chǔ)使用:設(shè)備信息

原創(chuàng):知識(shí)點(diǎn)總結(jié)性文章
創(chuàng)作不易鉴竭,請(qǐng)珍惜,之后會(huì)持續(xù)更新宜猜,不斷完善
個(gè)人比較喜歡做筆記和寫(xiě)總結(jié),畢竟好記性不如爛筆頭哈哈硝逢,這些文章記錄了我的IOS成長(zhǎng)歷程姨拥,希望能與大家一起進(jìn)步
溫馨提示:由于簡(jiǎn)書(shū)不支持目錄跳轉(zhuǎn),大家可通過(guò)command + F 輸入目錄標(biāo)題后迅速尋找到你所需要的內(nèi)容

目錄

  • 一趴捅、判斷iOS設(shè)備是否安裝了特定的app并跳轉(zhuǎn)
    • 1垫毙、應(yīng)用間相互跳轉(zhuǎn)應(yīng)用場(chǎng)景
    • 2霹疫、應(yīng)用間相互跳轉(zhuǎn)實(shí)現(xiàn)原理
    • 3拱绑、應(yīng)用A跳轉(zhuǎn)到應(yīng)用B
    • 4、跳轉(zhuǎn)到特定界面
    • 5丽蝎、從應(yīng)用B跳轉(zhuǎn)回應(yīng)用A
    • 6猎拨、常見(jiàn)Scheme
    • 7膀藐、跳轉(zhuǎn)到APP Store更新APP
  • 二、設(shè)備信息
    • 1红省、真機(jī)運(yùn)行效果
    • 2额各、能夠獲取到的設(shè)備信息
    • 3、獲取設(shè)備信息接口的具體實(shí)現(xiàn)
    • 4吧恃、UIDevice中對(duì)狀態(tài)信息的監(jiān)控
  • 三虾啦、電量信息
    • 1、真機(jī)運(yùn)行效果
    • 2痕寓、能夠獲取到的電量信息
    • 3傲醉、獲取電量信息接口的具體實(shí)現(xiàn)
  • 四、磁盤(pán)內(nèi)存信息
    • 1呻率、真機(jī)運(yùn)行效果
    • 2硬毕、能夠獲取到的磁盤(pán)內(nèi)存信息
    • 3、獲取磁盤(pán)內(nèi)存信息接口的具體實(shí)現(xiàn)
  • 五礼仗、CPU信息
    • 1吐咳、真機(jī)運(yùn)行在控制臺(tái)輸出結(jié)果
    • 2、能夠獲取到的CPU信息
    • 3元践、獲取CPU信息接口的具體實(shí)現(xiàn)
  • 六韭脊、網(wǎng)絡(luò)信息
    • 1、概念解釋
    • 2单旁、真機(jī)運(yùn)行效果
    • 3乾蓬、能夠獲取到的網(wǎng)絡(luò)信息
    • 4、獲取網(wǎng)絡(luò)信息接口的具體實(shí)現(xiàn)
    • 5慎恒、判斷IPv4和IPv6并獲取地址
  • Demo
  • 參考文獻(xiàn)

一任内、判斷iOS設(shè)備是否安裝了特定的app并跳轉(zhuǎn)

1切蟋、應(yīng)用間相互跳轉(zhuǎn)場(chǎng)景

  • 使用第三方用戶登錄强挫,跳轉(zhuǎn)到需授權(quán)的App,還需要返回到調(diào)用的程序牡辽,同時(shí)返回授權(quán)的用戶名粒氧、密碼越除,如QQ登錄,微信登錄等
  • 應(yīng)用程序推廣外盯,跳轉(zhuǎn)到另一個(gè)應(yīng)用程序(本機(jī)已經(jīng)安裝)摘盆,或者跳轉(zhuǎn)到APP Store并顯示應(yīng)用程序下載頁(yè)面(本機(jī)沒(méi)有安裝)
  • 第三方支付,跳轉(zhuǎn)到第三方支付App饱苟,如支付寶支付孩擂,微信支付
  • 內(nèi)容分享,跳轉(zhuǎn)到分享App的對(duì)應(yīng)頁(yè)面箱熬,如分享給微信好友类垦、分享給微信朋友圈狈邑、分享到微博
  • 顯示位置、地圖導(dǎo)航蚤认,跳轉(zhuǎn)到地圖應(yīng)用
  • 使用系統(tǒng)內(nèi)置程序米苹,跳轉(zhuǎn)到打電話、發(fā)短信砰琢、發(fā)郵件蘸嘶、Safari打開(kāi)網(wǎng)頁(yè)等內(nèi)置App中

2、應(yīng)用間相互跳轉(zhuǎn)實(shí)現(xiàn)原理

URL Schemes

在iOS中打開(kāi)一個(gè)應(yīng)用程序只需要拿到這個(gè)應(yīng)用程序的協(xié)議頭即可陪汽,所以我們只需配置應(yīng)用程序的協(xié)議頭即可亏较。通過(guò)設(shè)置跳轉(zhuǎn)到應(yīng)用B的URL Schemes(自定義的協(xié)議頭),應(yīng)用B將其自身“綁定”到一個(gè)自定義URL Schemes上掩缓,就可以從應(yīng)用A中利用應(yīng)用B的URL Schemes啟動(dòng)應(yīng)用B了雪情。

判斷是否安裝了應(yīng)用

知道appURL Schemes可以使用openUrl來(lái)獲取iOS是否安裝了某款軟件,比如這樣[[UIApplication sharedApplication] canOpenURL:@"damon://"]你辣,會(huì)返回一個(gè)bool值巡通,為true則安裝了,否則沒(méi)有安裝舍哄。

獲取app的url schemes

把相應(yīng)的appipa 安裝文件下載下來(lái)宴凉,把文件 .ipa的后綴改成.zip,然后解壓表悬,打開(kāi) Payload/xxx.app/Info.plist這個(gè)文件弥锄,找到 URL types下的URL Schemes 下的數(shù)組對(duì)應(yīng)的值就是這個(gè) appURL Scheme 了 。

驗(yàn)證一個(gè) URL Scheme 是否正確

在真機(jī)設(shè)備(此設(shè)備要安裝了待驗(yàn)證的 app)里面打開(kāi) Safari蟆沫,然后在地址欄中鍵入該應(yīng)用的 URL Scheme籽暇,后加 ://,比如 Weico 的饭庞,在地址欄中鍵入 weico:// 戒悠,然后點(diǎn)擊確定,如果能正常調(diào)用出 Weico舟山,即代表這個(gè) URL Scheme 正確可用绸狐。


3、應(yīng)用A跳轉(zhuǎn)到應(yīng)用B

判斷某個(gè)特定的App是否被安裝一般都是用來(lái)進(jìn)行跳轉(zhuǎn)或打開(kāi)的累盗,如果安裝了寒矿,我們?cè)撊绾螌?shí)現(xiàn)跳轉(zhuǎn)呢?

步驟一:用Xcode創(chuàng)建兩個(gè)iOS應(yīng)用程序項(xiàng)目若债,項(xiàng)目名稱分別為App-A符相、App-B
步驟二:選擇項(xiàng)目App-B -> TARGETS -> Info -> URL Types -> URL Schemes拆座,設(shè)置App-BURL SchemesAppB主巍。

AppB

步驟三:在應(yīng)用程序App-A中添加一個(gè)用來(lái)點(diǎn)擊跳轉(zhuǎn)的Button,并監(jiān)聽(tīng)點(diǎn)擊事件挪凑,添加跳轉(zhuǎn)代碼孕索。

- (void)jumpToAppB
{
    // 1.獲取應(yīng)用程序App-B的URL Scheme
    NSURL *appBUrl = [NSURL URLWithString:@"AppB://?AppA"];
    
    // 2.判斷手機(jī)中是否安裝了對(duì)應(yīng)程序
    // iOS10 以后,canOpenURL與openURL合并為一個(gè)躏碳,可以實(shí)現(xiàn)動(dòng)態(tài)跳轉(zhuǎn)不用配置
    if ([[UIApplication sharedApplication] canOpenURL:appBUrl])
    {
        NSLog(@"打開(kāi)應(yīng)用程序App-B");
    }
    else
    {
        NSLog(@"沒(méi)有安裝");
    }
}

步驟四:需要將跳轉(zhuǎn)的UrlScheme添加到白名單即可搞旭。添加方法:info.plist 增加LSApplicationQueriesSchemesarray類型),把要跳轉(zhuǎn)的app的UrlScheme加進(jìn)去菇绵。

UrlScheme

運(yùn)行效果如下:

從A跳轉(zhuǎn)到B

4肄渗、跳轉(zhuǎn)到特定界面

很多時(shí)候,我們做應(yīng)用程序之間的跳轉(zhuǎn)并不只是跳轉(zhuǎn)到其他程序就可以了咬最,而是要跳轉(zhuǎn)到其他程序的特定頁(yè)面上翎嫡。比如我們?cè)跒g覽網(wǎng)頁(yè)時(shí),會(huì)有分享到微信朋友圈或是分享給微信朋友永乌,這就需要跳轉(zhuǎn)到微信朋友圈界面或是微信朋友選擇界面惑申。具體如何做呢?

步驟一:在APP-B中創(chuàng)建兩個(gè)界面WriterViewControllerWasteMaterialsViewController翅雏。
步驟二:在應(yīng)用程序App-A中添加兩個(gè)用來(lái)點(diǎn)擊跳轉(zhuǎn)的Button圈驼,一個(gè)跳轉(zhuǎn)到WriterViewController,一個(gè)跳轉(zhuǎn)到WasteMaterialsViewController望几,并監(jiān)聽(tīng)點(diǎn)擊事件绩脆,添加跳轉(zhuǎn)代碼。

- (void)jumpToAppBWriterViewController
{
    // 1.獲取應(yīng)用程序App-B的Page1頁(yè)面的URL
    NSURL *appBUrl = [NSURL URLWithString:@"AppB://WriterViewController"];

    // 2.判斷手機(jī)中是否安裝了對(duì)應(yīng)程序并跳轉(zhuǎn)
    if ([[UIApplication sharedApplication] canOpenURL:appBUrl])
    {
        [[UIApplication sharedApplication] openURL:appBUrl options:@{UIApplicationOpenURLOptionsSourceApplicationKey : @YES} completionHandler:^(BOOL success) {

            if (!success)
            {

                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"不能完成跳轉(zhuǎn)" message:@"請(qǐng)確認(rèn)App已經(jīng)安裝" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleCancel handler:nil];
                [alertController addAction:cancelAction];
                [self  presentViewController:alertController animated:YES completion:nil];
            }
            else if(self.isBack)
            {
                [self dismissViewControllerAnimated:YES completion:nil];
            }
        }];
    }
    else
    {
        NSLog(@"沒(méi)有安裝");
    }
}
- (void)jumpToAppBWasteMaterialsViewController
{
    // 1.獲取應(yīng)用程序App-B的Page1頁(yè)面的URL
    NSURL *appBUrl = [NSURL URLWithString:@"AppB://WasteMaterialsViewController"];

    // 2.判斷手機(jī)中是否安裝了對(duì)應(yīng)程序并跳轉(zhuǎn)
    if ([[UIApplication sharedApplication] canOpenURL:appBUrl])
    {
        [[UIApplication sharedApplication] openURL:appBUrl options:@{UIApplicationOpenURLOptionsSourceApplicationKey : @YES} completionHandler:^(BOOL success) {

            if (!success)
            {

                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"不能完成跳轉(zhuǎn)" message:@"請(qǐng)確認(rèn)App已經(jīng)安裝" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleCancel handler:nil];
                [alertController addAction:cancelAction];
                [self  presentViewController:alertController animated:YES completion:nil];
            }
            else if(self.isBack)
            {
                [self dismissViewControllerAnimated:YES completion:nil];
            }
        }];
    }
    else
    {
        NSLog(@"沒(méi)有安裝");
    }
}

步驟三:在應(yīng)用App-B中通過(guò)AppDelegate監(jiān)聽(tīng)跳轉(zhuǎn)橄抹,進(jìn)行判斷靴迫,執(zhí)行不同頁(yè)面的跳轉(zhuǎn)。

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    NSString *sourceId = options[@"UIApplicationOpenURLOptionsSourceApplicationKey"];
    NSLog(@"openURL:url=%@;sourceId=%@;options=%@",url,sourceId,options);
    
    // 1.獲取導(dǎo)航欄控制器
    UINavigationController *rootNavigationVC = (UINavigationController *)self.window.rootViewController;

    // 2.每次跳轉(zhuǎn)前必須是在根控制器(細(xì)節(jié))
    [rootNavigationVC popToRootViewControllerAnimated:NO];

    // 3.根據(jù)字符串關(guān)鍵字來(lái)跳轉(zhuǎn)到不同頁(yè)面
    if ([url.absoluteString containsString:@"WriterViewController"]) //跳轉(zhuǎn)到應(yīng)用App-B的WriterViewController頁(yè)面
    {
        // 進(jìn)行跳轉(zhuǎn)
        WriterViewController *vc = [[WriterViewController alloc] init];
        [rootNavigationVC pushViewController:vc animated:YES];
    }
    else if ([url.absoluteString containsString:@"WasteMaterialsViewController"])// 跳轉(zhuǎn)到應(yīng)用App-B的WasteMaterialsViewController頁(yè)面
    {
        // 進(jìn)行跳轉(zhuǎn)
        WasteMaterialsViewController *vc = [[WasteMaterialsViewController alloc] init];
        [rootNavigationVC pushViewController:vc animated:YES];
    }

    return YES;
}

運(yùn)行效果如下:

跳轉(zhuǎn)到特定界面

5楼誓、從應(yīng)用B跳轉(zhuǎn)回應(yīng)用A

a矢劲、實(shí)現(xiàn)方案

我們想要從應(yīng)用B再跳轉(zhuǎn)回應(yīng)用A,那么在跳轉(zhuǎn)到應(yīng)用B的時(shí)候慌随,還應(yīng)將應(yīng)用A的URL Schemes傳遞過(guò)來(lái)芬沉,這樣我們才能判斷應(yīng)該跳轉(zhuǎn)回哪個(gè)應(yīng)用程序。我們指定一個(gè)傳遞URL的規(guī)則:協(xié)議頭://應(yīng)用B的URL Schemes?應(yīng)用A的URL Schemes阁猜。即:AppB://WriterViewController?AppA丸逸。AppB是跳轉(zhuǎn)過(guò)來(lái)的應(yīng)用App-BURL SchemesWriterViewController是用來(lái)區(qū)別跳轉(zhuǎn)頁(yè)面的標(biāo)識(shí)剃袍;? 是分割符黄刚;AppA是跳轉(zhuǎn)回的應(yīng)用App-AURL Schemes

我們根據(jù)傳遞來(lái)的數(shù)據(jù)民效,進(jìn)行反跳回去憔维。之前我們?cè)趹?yīng)用App-B中通過(guò)AppDelegate執(zhí)行不同頁(yè)面的跳轉(zhuǎn)涛救。在對(duì)應(yīng)方法中我們可以拿到完整的URL,在主控制器ViewController中設(shè)定一個(gè)屬性业扒,將該URL保存在主控制器中检吆。在將要跳轉(zhuǎn)的頁(yè)面控制器中定義一個(gè)屬性,用于接受程储、截取出跳轉(zhuǎn)回的應(yīng)用(即App-A)的URL Schemes蹭沛,執(zhí)行跳轉(zhuǎn)。


b章鲤、具體步驟

步驟一:因?yàn)槲覀兿胍D(zhuǎn)回應(yīng)用A摊灭,首先我們要先設(shè)置應(yīng)用App-AURL Schemes,將其設(shè)置為AppA败徊。同時(shí)在應(yīng)用App-B中添加白名單帚呼。
步驟二:App-B項(xiàng)目中的兩個(gè)頁(yè)面各添加一個(gè)Button,用于跳轉(zhuǎn)回App-A皱蹦。
步驟三:App-A中修改傳遞的URL萝挤,分別修改為:AppB://WriterViewController?AppAAppB://WasteMaterialsViewController?AppA根欧。
步驟四:在將要跳轉(zhuǎn)的頁(yè)面控制器WasteMaterialsViewControllerWriterViewController中定義一個(gè)屬性@property (nonatomic, copy) NSString *urlString;怜珍,用于接受、截取出跳轉(zhuǎn)回的應(yīng)用(即App-A)的URL Schemes凤粗,執(zhí)行跳轉(zhuǎn)酥泛。
步驟五:App-BAppDelegate中傳遞URL

// 進(jìn)行跳轉(zhuǎn)
WriterViewController *vc = [[WriterViewController alloc] init];
// 保存完整的App-A的URL給主控制器
vc.urlString = url.absoluteString;
[rootNavigationVC pushViewController:vc animated:YES];

步驟六:實(shí)現(xiàn)跳轉(zhuǎn)回APP-A的方法嫌拣。

- (void)backToAppA
{
    // 1.拿到對(duì)應(yīng)應(yīng)用程序的URL Scheme
    NSString *urlSchemeString = [[self.urlString componentsSeparatedByString:@"?"] lastObject];
    NSString *urlString = [urlSchemeString stringByAppendingString:@"://"];
    
    // 2.獲取對(duì)應(yīng)應(yīng)用程序的URL
    NSURL *appAUrl = [NSURL URLWithString:urlString];
    
    // 3.判斷是否可以打開(kāi)
    if (appAUrl && [[UIApplication sharedApplication] canOpenURL:appAUrl])
    {
        [[UIApplication sharedApplication] openURL:appAUrl options:@{UIApplicationOpenURLOptionsSourceApplicationKey : @YES} completionHandler:^(BOOL success) {

            if (!success)
            {

                UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"不能完成跳轉(zhuǎn)" message:@"請(qǐng)確認(rèn)App已經(jīng)安裝" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"確定"style:UIAlertActionStyleCancel handler:nil];
                [alertController addAction:cancelAction];
                [self  presentViewController:alertController animated:YES completion:nil];
            }
            else if(self.isBack)
            {
                [self dismissViewControllerAnimated:YES completion:nil];
            }
        }];
    }
    else
    {
        NSLog(@"沒(méi)有安裝");
    }
}

運(yùn)行效果如下:

跳轉(zhuǎn)回App-A

6柔袁、常見(jiàn)Scheme

//調(diào)用郵件客戶端(Apple Mail)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://admin@eyecm.com"]];

//撥號(hào)(Phone Number)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://10086"]];

//調(diào)用短信(SMS)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms:10086"]];

//調(diào)用瀏覽器(Safari Browser)
NSURL*url =[NSURL URLWithString:@"http://eyecm.com"];
[[UIApplication sharedApplication] openURL:url];

//調(diào)用應(yīng)用商店(AppStore)
NSURL*appStoreUrl =[NSURL URLWithString:@"http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=291586600&amp;amp;mt=8"];
[[UIApplication sharedApplication] openURL:appStoreUrl];

7、跳轉(zhuǎn)到APP Store更新APP

a异逐、真機(jī)運(yùn)行效果
控制臺(tái)輸出結(jié)果
2020-10-29 10:39:19.310354+0800 DeviceInfoDemo[749:64988] 接口返回的APP信息包括:{
    advisories =     (
        "\U9891\U7e41/\U5f3a\U70c8\U7684\U6210\U4eba/\U6027\U6697\U793a\U9898\U6750"
    );
    appletvScreenshotUrls =     (
    );
    artistId = 614694882;
    artistName = WeChat;
    artistViewUrl = "https://apps.apple.com/cn/developer/wechat/id614694882?uo=4";
    averageUserRating = "4.4047900000000002052047420875169336795";
    averageUserRatingForCurrentVersion = "4.4047900000000002052047420875169336795";
    bundleId = "com.tencent.xin";
    contentAdvisoryRating = "17+";
    currency = CNY;
    currentVersionReleaseDate
2020-10-29 10:39:19.311923+0800 DeviceInfoDemo[749:64988] APP的當(dāng)前版本:1.0捶索,AppStore 上軟件的最新版本:7.0.17
2020-10-29 10:39:23.520783+0800 DeviceInfoDemo[749:64988] 新版本更新內(nèi)容:本次更新:
- 可前往“我 > 設(shè)置”開(kāi)啟青少年模式,并設(shè)置青少年模式下的訪問(wèn)范圍灰瞻。
- 可以在會(huì)話的表情面板搜索表情腥例。

最近更新:
- 可跟隨系統(tǒng)的設(shè)置,切換為深色模式酝润。
- 優(yōu)化了語(yǔ)音消息的發(fā)送體驗(yàn)燎竖,上滑轉(zhuǎn)文字更方便了。
2020-10-29 10:39:31.858534+0800 DeviceInfoDemo[749:64926] AppStore 上APP的地址:https://apps.apple.com/cn/app/%E5%BE%AE%E4%BF%A1/id414478124?uo=4
2020-10-29 10:39:31.882374+0800 DeviceInfoDemo[749:64926] 進(jìn)入到了APP Store更新APP
APP顯示的信息
更新內(nèi)容的提示
跳轉(zhuǎn)到App Store

b要销、判斷是否最新版本號(hào)(大于或等于為最新)
- (BOOL)isLastestVersion:(NSString *)currentVersion compare:(NSString *)lastestVersion
{
    if (currentVersion && lastestVersion)
    {
        // 拆分成數(shù)組
        NSMutableArray *currentItems = [[currentVersion componentsSeparatedByString:@"."] mutableCopy];
        NSMutableArray *lastestItems = [[lastestVersion componentsSeparatedByString:@"."] mutableCopy];
        
        // 如果數(shù)量不一樣補(bǔ)0
        NSInteger currentCount = currentItems.count;
        NSInteger lastestCount = lastestItems.count;
        
        if (currentCount != lastestCount)
        {
            // 取絕對(duì)值
            NSInteger count = labs(currentCount - lastestCount);
            for (int i = 0; i < count; ++i)
            {
                if (currentCount > lastestCount)
                {
                    [lastestItems addObject:@"0"];
                }
                else
                {
                    [currentItems addObject:@"0"];
                }
            }
        }
        
        // 依次比較
        BOOL isLastest = YES;
        for (int i = 0; i < currentItems.count; ++i)
        {
            NSString *currentItem = currentItems[i];
            NSString *lastestItem = lastestItems[i];
            if (currentItem.integerValue != lastestItem.integerValue)
            {
                isLastest = currentItem.integerValue > lastestItem.integerValue;
                break;
            }
        }
        return isLastest;
    }
    return NO;
}

c构回、 跳轉(zhuǎn)到App Store更新APP
// 跳轉(zhuǎn)到App Store的鏈接itms-apps://itunes.apple.com/cn/app/id(你的APPID)
// AppID的查詢方法為APP Store里面的分享鏈接 https://apps.apple.com/cn/app/%E7%9F%A5%E4%B9%8E-%E6%9C%89%E9%97%AE%E9%A2%98-%E4%B8%8A%E7%9F%A5%E4%B9%8E/id432274380
- (void)checkVersion
{
    // 你的項(xiàng)目ID
    NSString *storeAppID = @"414478124";// 微信的AppID
    
    // 參數(shù)appid指的是你在app創(chuàng)建后的唯一標(biāo)識(shí),在iTunes Connect里可以查找到此信息
    NSString *storeAppIDString = [NSString stringWithFormat:@"http://itunes.apple.com/cn/lookup?id=%@",storeAppID];
    NSURL *url = [NSURL URLWithString:storeAppIDString];
    
    // 聯(lián)網(wǎng)檢測(cè)項(xiàng)目在AppStore上的版本號(hào)
    // 此接口將返回一個(gè)JSON格式的字串內(nèi)容,其中一個(gè)就是版本信息纤掸,如"version":"1.2.0"
    [[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSDictionary * dataDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
        NSArray *results = dataDic[@"results"];
        if (results && results.count > 0)
        {
            NSDictionary *response = results.firstObject;
            
            NSLog(@"接口返回的APP信息包括:%@",response);
            
            // APP的當(dāng)前版本
            NSString *currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
            // AppStore 上軟件的最新版本
            NSString *lastestVersion = response[@"version"];
            
            NSLog(@"APP的當(dāng)前版本:%@脐供,AppStore 上軟件的最新版本:%@",currentVersion,lastestVersion);
            
            if (currentVersion && lastestVersion && ![self isLastestVersion:currentVersion compare:lastestVersion])
            {
                // 新版本更新內(nèi)容
                NSString *releaseNotes = response[@"releaseNotes"];
                NSString *alertContent = [NSString stringWithFormat:@"%@\n\n是否前往 AppStore 更新版本?",releaseNotes];
                NSLog(@"新版本更新內(nèi)容:%@",releaseNotes);
                
                // 給出提示是否前往 AppStore 更新
                UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"檢測(cè)到有版本更新" message:alertContent preferredStyle:UIAlertControllerStyleAlert];
                
                [alert addAction:[UIAlertAction actionWithTitle:@"前往" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
                    
                    // AppStore 上APP的地址
                    NSString *trackViewUrl = response[@"trackViewUrl"];
                    NSLog(@"AppStore 上APP的地址:%@",trackViewUrl);
                    if (trackViewUrl)
                    {
                        NSURL *appStoreURL = [NSURL URLWithString:trackViewUrl];
                        if ([[UIApplication sharedApplication] canOpenURL:appStoreURL])
                        {
                            [[UIApplication sharedApplication] openURL:appStoreURL options:@{} completionHandler:nil];
                            NSLog(@"進(jìn)入到了APP Store更新APP");
                        }
                    }
                }]];
                [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
                });
            }
        }
    }] resume];
}

二借跪、設(shè)備信息

1政己、真機(jī)運(yùn)行效果

a、控制臺(tái)輸出結(jié)果
2020-09-07 15:25:22.604649+0800 DeviceInfoDemo[4543:775271] infoKey:device_model---infoValue:iPhone11,8
2020-09-07 15:25:22.605227+0800 DeviceInfoDemo[4543:775271] infoKey:localizedModel---infoValue:iPhone
2020-09-07 15:25:22.605661+0800 DeviceInfoDemo[4543:775271] infoKey:設(shè)備型號(hào)---infoValue:iPhone XR
2020-09-07 15:25:22.608200+0800 DeviceInfoDemo[4543:775271] infoKey:設(shè)備名稱---infoValue:不才
2020-09-07 15:25:22.608756+0800 DeviceInfoDemo[4543:775271] infoKey:設(shè)備顏色(Private API)---infoValue:1
2020-09-07 15:25:22.609098+0800 DeviceInfoDemo[4543:775271] infoKey:設(shè)備外殼顏色(Private API)---infoValue:2
2020-09-07 15:25:22.609425+0800 DeviceInfoDemo[4543:775271] infoKey:app版本號(hào)---infoValue:1.0
2020-09-07 15:25:22.609687+0800 DeviceInfoDemo[4543:775271] infoKey:當(dāng)前系統(tǒng)名稱---infoValue:iOS
2020-09-07 15:25:22.609970+0800 DeviceInfoDemo[4543:775271] infoKey:當(dāng)前系統(tǒng)版本號(hào)---infoValue:13.5.1
2020-09-07 15:25:22.610195+0800 DeviceInfoDemo[4543:775271] infoKey:設(shè)備支持最低系統(tǒng)版本---infoValue:12.0
2020-09-07 15:25:22.610417+0800 DeviceInfoDemo[4543:775271] infoKey:設(shè)備支持的最高系統(tǒng)版本---infoValue:(null)
2020-09-07 15:25:22.618473+0800 DeviceInfoDemo[4543:775271] infoKey:能否打電話---infoValue:能
2020-09-07 15:25:22.618668+0800 DeviceInfoDemo[4543:775271] infoKey:設(shè)備上次重啟的時(shí)間---infoValue:Sun Sep  6 15:33:23 2020
2020-09-07 15:25:22.618792+0800 DeviceInfoDemo[4543:775271] infoKey:當(dāng)前設(shè)備的總線頻率---infoValue:0
2020-09-07 15:25:22.618895+0800 DeviceInfoDemo[4543:775271] infoKey:當(dāng)前設(shè)備的主存大小---infoValue:0

b垦梆、APP顯示的信息
Hardware

2匹颤、能夠獲取到的設(shè)備信息

a仅孩、工具類提供的獲取設(shè)備信息的接口
/** 獲取用戶的本地化信息:貨幣類型托猩,國(guó)家单寂,語(yǔ)言夺脾,數(shù)字房交,日期格式的格式化 */
- (void)localInfo;
/** 獲取設(shè)備型號(hào) */
- (const NSString *)getDeviceName;
/** 獲取設(shè)備顏色 */
- (NSString *)getDeviceColor;
/** 獲取設(shè)備外殼顏色 */
- (NSString *)getDeviceEnclosureColor;
/** 獲取設(shè)備Model */
- (NSString *)getDeviceModel;
/** 獲取設(shè)備裝機(jī)時(shí)的系統(tǒng)版本(最低支持版本) */
- (const NSString *)getInitialFirmware;
/** 獲取設(shè)備可支持的最高系統(tǒng)版本 */
- (const NSString *)getLatestFirmware;
/** 獲取設(shè)備上次重啟的時(shí)間 */
- (NSDate *)getSystemUptime;
/** 獲取總線程頻率 */
- (NSUInteger)getBusFrequency;
/** 獲取當(dāng)前設(shè)備主存 */
- (NSUInteger)getRamSize;

b酥筝、調(diào)用接口獲取信息
- (void)setupHardwareInfo
{
    // 獲取用戶的本地化信息:貨幣類型坪仇,國(guó)家轮蜕,語(yǔ)言举瑰,數(shù)字四濒,日期格式的格式化
    [[DeviceInfoManager sharedManager] localInfo];

    // 獲取DeviceModel
    NSString *device_model = [[DeviceInfoManager sharedManager] getDeviceModel];
    [self addInfoWithKey:@"device_model" infoValue:device_model];
    
    // 獲取localizedModel
    NSString *localizedModel = [UIDevice currentDevice].localizedModel;
    [self addInfoWithKey:@"localizedModel" infoValue:localizedModel];
    
    // 獲取設(shè)備型號(hào)
    const NSString *deviceName = [[DeviceInfoManager sharedManager] getDeviceName];
    [self addInfoWithKey:@"設(shè)備型號(hào)" infoValue:[deviceName copy]];
    
    // 獲取設(shè)備名稱
    NSString *iPhoneName = [UIDevice currentDevice].name;
    [self addInfoWithKey:@"設(shè)備名稱" infoValue:iPhoneName];
    
    // 獲取設(shè)備顏色
    NSString *deviceColor = [[DeviceInfoManager sharedManager] getDeviceColor];
    [self addInfoWithKey:@"設(shè)備顏色(Private API)" infoValue:deviceColor];
    
    // 獲取設(shè)備外殼顏色
    NSString *deviceEnclosureColor = [[DeviceInfoManager sharedManager] getDeviceEnclosureColor];
    [self addInfoWithKey:@"設(shè)備外殼顏色(Private API)" infoValue:deviceEnclosureColor];
    
    // 獲取app名稱
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    NSLog(@"App應(yīng)用名稱:%@", appName);
    
    // 獲取app版本號(hào)
    NSString *appVerion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    [self addInfoWithKey:@"app版本號(hào)" infoValue:appVerion];
    
    // 獲取app應(yīng)用Build版本號(hào)
    NSString *appBuild = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    NSLog(@"app應(yīng)用Build版本號(hào):%@", appBuild);
    
    // 獲取當(dāng)前系統(tǒng)名稱
    NSString *systemName = [UIDevice currentDevice].systemName;
    [self addInfoWithKey:@"當(dāng)前系統(tǒng)名稱" infoValue:systemName];
    
    // 當(dāng)前系統(tǒng)版本號(hào)
    NSString *systemVersion = [UIDevice currentDevice].systemVersion;
    [self addInfoWithKey:@"當(dāng)前系統(tǒng)版本號(hào)" infoValue:systemVersion];
    
    // 設(shè)備支持最低系統(tǒng)版本
    const NSString *initialFirmware = [[DeviceInfoManager sharedManager] getInitialFirmware];
    [self addInfoWithKey:@"設(shè)備支持最低系統(tǒng)版本" infoValue:[initialFirmware copy]];
    
    // 設(shè)備支持的最高系統(tǒng)版本
    const NSString *latestFirmware = [[DeviceInfoManager sharedManager] getLatestFirmware];
    [self addInfoWithKey:@"設(shè)備支持的最高系統(tǒng)版本" infoValue:[latestFirmware copy]];
    
    // 能否打電話
    BOOL canMakePhoneCall = [DeviceInfoManager sharedManager].canMakePhoneCall;
    [self addInfoWithKey:@"能否打電話" infoValue:@(canMakePhoneCall ? "能" : "不能")];
    
    // 獲取設(shè)備上次重啟的時(shí)間
    NSDate *systemUptime = [[DeviceInfoManager sharedManager] getSystemUptime];
    [self addInfoWithKey:@"設(shè)備上次重啟的時(shí)間" infoValue:systemUptime];
    
    // 當(dāng)前設(shè)備的總線頻率
    NSUInteger busFrequency = [[DeviceInfoManager sharedManager] getBusFrequency];
    [self addInfoWithKey:@"當(dāng)前設(shè)備的總線頻率" infoValue:@(busFrequency)];
    
    // 當(dāng)前設(shè)備的主存大小(隨機(jī)存取存儲(chǔ)器(Random Access Memory))
    NSUInteger ramSize = [[DeviceInfoManager sharedManager] getRamSize];
    [self addInfoWithKey:@"當(dāng)前設(shè)備的主存大小" infoValue:@(ramSize)];
}

3船侧、獲取設(shè)備信息接口的具體實(shí)現(xiàn)

a欠气、需要導(dǎo)入的頭文件
// 下面是獲取mac地址需要導(dǎo)入的頭文件
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#import <sys/sockio.h>
#import <sys/ioctl.h>
#import <arpa/inet.h>

#import "sys/utsname.h" //獲取設(shè)備Model
#import <AdSupport/AdSupport.h> //獲取廣告標(biāo)識(shí)符
#include <ifaddrs.h> //獲取ip需要的頭文件
#include <mach/mach.h> //獲取CPU信息所需要引入的頭文件

b、方法的實(shí)現(xiàn)
獲取用戶的本地化信息:貨幣類型镜撩,國(guó)家预柒,語(yǔ)言,數(shù)字袁梗,日期格式的格式化
- (void)localInfo
{
    NSArray *languageArray = [NSLocale preferredLanguages];
    NSString *language = [languageArray objectAtIndex:0];
    NSLog(@"語(yǔ)言:%@", language);//en
    
    NSLocale *local = [NSLocale currentLocale];
    NSString *country = [local localeIdentifier];
    NSLog(@"國(guó)家:%@", country); //en_US
}
獲取設(shè)備型號(hào)
- (const NSString *)getDeviceName
{
    return [[DeviceDataLibrery sharedLibrery] getDiviceName];
}
獲取設(shè)備顏色
- (NSString *)getDeviceColor
{
    return [self getDeviceColorWithKey:@"DeviceColor"];
}
獲取設(shè)備外殼顏色宜鸯,私有API,上線會(huì)被拒
- (NSString *)getDeviceEnclosureColor
{
    return [self getDeviceColorWithKey:@"DeviceEnclosureColor"];
}
獲取設(shè)備Model
- (NSString *)getDeviceModel
{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    return deviceModel;
}
獲取設(shè)備裝機(jī)時(shí)的系統(tǒng)版本(最低支持版本)
- (const NSString *)getInitialFirmware
{
    return [[DeviceDataLibrery sharedLibrery] getInitialVersion];
}
獲取設(shè)備可支持的最高系統(tǒng)版本
- (const NSString *)getLatestFirmware
{
    return [[DeviceDataLibrery sharedLibrery] getLatestVersion];
}
能否打電話
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
- (BOOL)canMakePhoneCall
{
    __block BOOL can;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        can = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel://"]];
    });
    return can;
}
#endif
獲取設(shè)備上次重啟的時(shí)間
- (NSDate *)getSystemUptime
{
    NSTimeInterval time = [[NSProcessInfo processInfo] systemUptime];
    return [[NSDate alloc] initWithTimeIntervalSinceNow:(0 - time)];
}
獲取總線程頻率
- (NSUInteger)getBusFrequency
{
    return [self getSystemInfo:HW_BUS_FREQ];
}
獲取當(dāng)前設(shè)備主存
- (NSUInteger)getRamSize
{
    return [self getSystemInfo:HW_MEMSIZE];
}
獲取設(shè)備顏色遮怜,私有API淋袖,上線會(huì)被拒
- (NSString *)getDeviceColorWithKey:(NSString *)key
{
    UIDevice *device = [UIDevice currentDevice];
    SEL selector = NSSelectorFromString(@"deviceInfoForKey:");
    if (![device respondsToSelector:selector])
    {
        selector = NSSelectorFromString(@"_deviceInfoForKey:");
    }
    
    if ([device respondsToSelector:selector])
    {
        // 消除警告“performSelector may cause a leak because its selector is unknown”
        IMP imp = [device methodForSelector:selector];
        NSString * (*func)(id, SEL, NSString *) = (void *)imp;
        
        return func(device, selector, key);
    }
    return @"unKnown";
}
獲取設(shè)備信息
- (NSUInteger)getSystemInfo:(uint)typeSpecifier
{
    size_t size = sizeof(int);
    int result;
    int mib[2] = {CTL_HW, typeSpecifier};
    sysctl(mib, 2, &result, &size, NULL, 0);
    return (NSUInteger)result;
}

4、UIDevice中對(duì)狀態(tài)信息的監(jiān)控

a锯梁、真機(jī)運(yùn)行在控制臺(tái)的輸出結(jié)果
2020-10-28 18:17:33.877164+0800 DeviceInfoDemo[621:101454] 近距離
2020-10-28 18:17:36.834020+0800 DeviceInfoDemo[621:101454] 遠(yuǎn)距離
2020-10-28 18:17:36.954133+0800 DeviceInfoDemo[621:101454] 設(shè)備方向改變

b即碗、添加狀態(tài)通知:即將某種狀態(tài)的監(jiān)控信息添加到通知中心
- (void)registerNotification
{
    // 添加設(shè)備方向的監(jiān)控通知,狀態(tài)發(fā)生變化是就會(huì)自動(dòng)調(diào)用對(duì)應(yīng)的方法執(zhí)行
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeOrientation) name:UIDeviceOrientationDidChangeNotification object:nil];
    
    // 添加距離狀態(tài)的監(jiān)控通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(changeProximityState) name:UIDeviceProximityStateDidChangeNotification object:nil];
}

c陌凳、開(kāi)啟監(jiān)控開(kāi)關(guān): 狀態(tài)通知都對(duì)應(yīng)有一個(gè)開(kāi)關(guān)來(lái)控制是否開(kāi)啟對(duì)應(yīng)的監(jiān)控和通知
- (void)openNotification
{
    //打開(kāi)設(shè)備方向監(jiān)測(cè)拜姿,這是用方法控制
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

    //不需要時(shí)可以關(guān)閉設(shè)備方向監(jiān)控
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];

    //打開(kāi)電池狀態(tài)和電池電量監(jiān)測(cè)開(kāi)關(guān),不需要時(shí)可以關(guān)閉
    [UIDevice currentDevice].batteryMonitoringEnabled=YES;

    //打開(kāi)手機(jī)距離傳感器監(jiān)測(cè)開(kāi)關(guān)冯遂,不需要時(shí)可以關(guān)閉
    [UIDevice currentDevice].proximityMonitoringEnabled=YES;
}

d蕊肥、狀態(tài)發(fā)生變化是就會(huì)自動(dòng)調(diào)用對(duì)應(yīng)的方法執(zhí)行
設(shè)備方向改變時(shí)調(diào)用該方法
-(void)changeOrientation
{
    NSLog(@"設(shè)備方向改變");
}
設(shè)備離用戶的距離狀態(tài)發(fā)生變化時(shí)調(diào)用該方法
- (void)changeProximityState
{
    if ([UIDevice currentDevice].proximityState)
    {
        NSLog(@"近距離");
    }
    else
    {
        NSLog(@"遠(yuǎn)距離");
    }
}

三、電量信息

1、真機(jī)運(yùn)行效果

a壁却、控制臺(tái)輸出結(jié)果
2020-09-07 16:07:41.215870+0800 DeviceInfoDemo[4630:791750] 電池狀態(tài)改變批狱,reload對(duì)應(yīng)的cell,進(jìn)行更新UI操作
2020-09-07 16:07:41.216055+0800 DeviceInfoDemo[4630:791750] 電池狀態(tài)改變展东,reload對(duì)應(yīng)的cell赔硫,進(jìn)行更新UI操作
2020-09-07 16:07:41.216303+0800 DeviceInfoDemo[4630:791750] infoKey:電池電量---infoValue:0.85
2020-09-07 16:07:41.216456+0800 DeviceInfoDemo[4630:791750] infoKey:電池容量---infoValue:2942 mA
2020-09-07 16:07:41.216560+0800 DeviceInfoDemo[4630:791750] infoKey:當(dāng)前電池剩余電量---infoValue:2500.70 mA
2020-09-07 16:07:41.216729+0800 DeviceInfoDemo[4630:791750] infoKey:電池電壓---infoValue:0.00 V
2020-09-07 16:07:41.216871+0800 DeviceInfoDemo[4630:791750] infoKey:電池狀態(tài)---infoValue:Charging

b、APP顯示的信息
電量

2盐肃、能夠獲取到的電量信息

a爪膊、工具類提供的獲取電量信息的接口
聲明委托
@protocol BatteryInfoDelegate

- (void)batteryStatusUpdated;

@end

@property (nonatomic, weak) id<BatteryInfoDelegate> delegate;
電量術(shù)語(yǔ)
// 電池容量,單位 mA 毫安
@property (nonatomic, assign) NSUInteger capacity;
// 電池電壓砸王,單位 V 福特
@property (nonatomic, assign) CGFloat voltage;
// 電池電量
@property (nonatomic, assign) NSUInteger levelPercent;
// 當(dāng)前電池剩余電量
@property (nonatomic, assign) NSUInteger levelMAH;
@property (nonatomic, copy)   NSString *status;
監(jiān)測(cè)電池電量
/** 開(kāi)始監(jiān)測(cè)電池電量 */
- (void)startBatteryMonitoring;
/** 停止監(jiān)測(cè)電池電量 */
- (void)stopBatteryMonitoring;

b推盛、調(diào)用接口獲取信息
獲取電池信息
- (void)setupBatteryInfo
{
    BatteryInfoManager *batteryManager = [BatteryInfoManager sharedManager];
    batteryManager.delegate = self;
    // 開(kāi)始監(jiān)測(cè)電池電量
    [batteryManager startBatteryMonitoring];
    
    // 獲得電池電量
    CGFloat batteryLevel = [[UIDevice currentDevice] batteryLevel];
    NSString *levelValue = [NSString stringWithFormat:@"%.2f", batteryLevel];
    [self addInfoWithKey:@"電池電量" infoValue:levelValue];
    
    // 獲得電池容量
    NSInteger batteryCapacity = batteryManager.capacity;
    NSString *capacityValue = [NSString stringWithFormat:@"%ld mA", batteryCapacity];
    [self addInfoWithKey:@"電池容量" infoValue:capacityValue];
    
    // 獲得當(dāng)前電池剩余電量
    CGFloat batteryMAH = batteryCapacity * batteryLevel;
    NSString *mahValue = [NSString stringWithFormat:@"%.2f mA", batteryMAH];
    [self addInfoWithKey:@"當(dāng)前電池剩余電量" infoValue:mahValue];
    
    // 獲得電池電壓
    CGFloat batteryVoltage = batteryManager.voltage;
    NSString *voltageValue = [NSString stringWithFormat:@"%.2f V", batteryVoltage];
    [self addInfoWithKey:@"電池電壓" infoValue:voltageValue];
    
    // 獲得電池狀態(tài)
    NSString *batterStatus = batteryManager.status ? : @"unkonwn";
    [self addInfoWithKey:@"電池狀態(tài)" infoValue:batterStatus];
}
當(dāng)電池狀態(tài)改變時(shí),會(huì)調(diào)用該方法谦铃,應(yīng)該在此處reload對(duì)應(yīng)的cell耘成,進(jìn)行更新UI操作
- (void)batteryStatusUpdated
{
    NSLog(@"電池狀態(tài)改變,reload對(duì)應(yīng)的cell驹闰,進(jìn)行更新UI操作");
}

3瘪菌、獲取電量信息接口的具體實(shí)現(xiàn)

a、監(jiān)測(cè)電池電量
- (void)startBatteryMonitoring
{
    if (!self.batteryMonitoringEnabled)
    {
        self.batteryMonitoringEnabled = YES;
        
        UIDevice *device = [UIDevice currentDevice];
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelUpdated:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryStatusUpdated:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
        
        [device setBatteryMonitoringEnabled:YES];
        
        // If by any chance battery value is available - update it immediately
        if ([device batteryState] != UIDeviceBatteryStateUnknown)
        {
            [self doUpdateBatteryStatus];
        }
    }
}

b嘹朗、電池狀態(tài)更改時(shí)調(diào)用的方法
電池電量改變
- (void)batteryLevelUpdated:(NSNotification*)notification
{
    [self doUpdateBatteryStatus];
}
電池狀態(tài)改變
- (void)batteryStatusUpdated:(NSNotification*)notification
{
    [self doUpdateBatteryStatus];
}
更新電池狀態(tài)
- (void)doUpdateBatteryStatus
{
    float batteryMultiplier = [[UIDevice currentDevice] batteryLevel];
    self.levelPercent = batteryMultiplier * 100;
    self.levelMAH =  self.capacity * batteryMultiplier;
    
    switch ([[UIDevice currentDevice] batteryState])
    {
        case UIDeviceBatteryStateCharging:// 充電
            if (self.levelPercent == 100)
            {
                self.status = @"Fully charged";
            }
            else
            {
                self.status = @"Charging";
            }
            break;
        case UIDeviceBatteryStateFull:// 滿電
            self.status = @"Fully charged";
            break;
        case UIDeviceBatteryStateUnplugged:// 未插入
            self.status = @"Unplugged";
            break;
        case UIDeviceBatteryStateUnknown:// 未知
            self.status = @"Unknown";
            break;
    }
    
    // 狀態(tài)更改
    [self.delegate batteryStatusUpdated];
}

四师妙、磁盤(pán)內(nèi)存信息

1、真機(jī)運(yùn)行效果

a屹培、控制臺(tái)輸出結(jié)果
2020-09-07 18:13:35.435340+0800 DeviceInfoDemo[5009:838778] infoKey:當(dāng)前 App 所占內(nèi)存空間---infoValue:320 bytes
2020-09-07 18:13:35.435774+0800 DeviceInfoDemo[5009:838778] infoKey:磁盤(pán)總空間---infoValue:== 122060.27 MB == 119.20 GB
2020-09-07 18:13:35.436224+0800 DeviceInfoDemo[5009:838778] infoKey:磁盤(pán)已使用空間---infoValue: == 88011.07 MB == 85.95 GB
2020-09-07 18:13:35.436491+0800 DeviceInfoDemo[5009:838778] infoKey:磁盤(pán)空閑空間---infoValue: 34049.20 MB == 33.25 GB
2020-09-07 18:13:35.436622+0800 DeviceInfoDemo[5009:838778] infoKey:系統(tǒng)總內(nèi)存空間---infoValue: 2831.33 MB == 2.76 GB
2020-09-07 18:13:35.436802+0800 DeviceInfoDemo[5009:838778] infoKey:空閑的內(nèi)存空間---infoValue: 101.25 MB == 0.10 GB
2020-09-07 18:19:32.184034+0800 DeviceInfoDemo[5032:841261] infoKey:已使用的內(nèi)存空間---infoValue: 2083.86 MB == 2.03 GB
2020-09-07 18:13:35.437295+0800 DeviceInfoDemo[5009:838778] infoKey:活躍的內(nèi)存---infoValue:正在使用或者很短時(shí)間內(nèi)被使用過(guò) 814.98 MB == 0.79 GB
2020-09-07 18:13:35.437410+0800 DeviceInfoDemo[5009:838778] infoKey:最近使用過(guò)---infoValue:但是目前處于不活躍狀態(tài)的內(nèi)存 725.95 MB == 0.71 GB
2020-09-07 18:13:35.437514+0800 DeviceInfoDemo[5009:838778] infoKey:用來(lái)存放內(nèi)核和數(shù)據(jù)結(jié)構(gòu)的內(nèi)存---infoValue:framework默穴、用戶級(jí)別的應(yīng)用無(wú)法分配 612.47 MB == 0.60 GB
2020-09-07 18:13:35.437619+0800 DeviceInfoDemo[5009:838778] infoKey:可釋放的內(nèi)存空間:內(nèi)存吃緊自動(dòng)釋放---infoValue:大對(duì)象存放所需的大塊內(nèi)存空間 9.88 MB == 0.01 GB

b、APP顯示的信息
image.png

2惫谤、能夠獲取到的磁盤(pán)內(nèi)存信息

a壁顶、工具類提供的獲取磁盤(pán)內(nèi)存信息的接口
磁盤(pán)
/** 獲取本 App 所占磁盤(pán)空間 */
- (NSString *)getApplicationSize;
/** 獲取磁盤(pán)總空間 */
- (int64_t)getTotalDiskSpace;
/** 獲取未使用的磁盤(pán)空間 */
- (int64_t)getFreeDiskSpace;
/** 獲取已使用的磁盤(pán)空間 */
- (int64_t)getUsedDiskSpace;
內(nèi)存
/** 獲取總內(nèi)存空間 */
- (int64_t)getTotalMemory;
/** 獲取活躍的內(nèi)存空間 */
- (int64_t)getActiveMemory;
/** 獲取不活躍的內(nèi)存空間 */
- (int64_t)getInActiveMemory;
/** 獲取空閑的內(nèi)存空間 */
- (int64_t)getFreeMemory;
/** 獲取正在使用的內(nèi)存空間 */
- (int64_t)getUsedMemory;
/** 獲取存放內(nèi)核的內(nèi)存空間 */
- (int64_t)getWiredMemory;
/** 獲取可釋放的內(nèi)存空間 */
- (int64_t)getPurgableMemory;

b、調(diào)用接口獲取信息
- (void)setupDiskInfo
{
    // 獲得當(dāng)前App所占內(nèi)存空間
    NSString *applicationSize = [[DeviceInfoManager sharedManager] getApplicationSize];
    [self addInfoWithKey:@"當(dāng)前 App 所占內(nèi)存空間" infoValue:applicationSize];
    
    // 獲得磁盤(pán)總空間
    int64_t totalDisk = [[DeviceInfoManager sharedManager] getTotalDiskSpace];
    NSString *totalDiskInfo = [NSString stringWithFormat:@"== %.2f MB == %.2f GB", totalDisk/1024/1024.0, totalDisk/1024/1024/1024.0];
    [self addInfoWithKey:@"磁盤(pán)總空間" infoValue:totalDiskInfo];
    
    // 獲得磁盤(pán)已使用空間
    int64_t usedDisk = [[DeviceInfoManager sharedManager] getUsedDiskSpace];
    NSString *usedDiskInfo = [NSString stringWithFormat:@" == %.2f MB == %.2f GB", usedDisk/1024/1024.0, usedDisk/1024/1024/1024.0];
    [self addInfoWithKey:@"磁盤(pán)已使用空間" infoValue:usedDiskInfo];
    
    // 獲得磁盤(pán)空閑空間
    int64_t freeDisk = [[DeviceInfoManager sharedManager] getFreeDiskSpace];
    NSString *freeDiskInfo = [NSString stringWithFormat:@" %.2f MB == %.2f GB", freeDisk/1024/1024.0, freeDisk/1024/1024/1024.0];
    [self addInfoWithKey:@"磁盤(pán)空閑空間" infoValue:freeDiskInfo];
    
    // 系統(tǒng)總內(nèi)存空間
    int64_t totalMemory = [[DeviceInfoManager sharedManager] getTotalMemory];
    NSString *totalMemoryInfo = [NSString stringWithFormat:@" %.2f MB == %.2f GB", totalMemory/1024/1024.0, totalMemory/1024/1024/1024.0];
    [self addInfoWithKey:@"系統(tǒng)總內(nèi)存空間" infoValue:totalMemoryInfo];
    
    // 獲得空閑的內(nèi)存空間
    int64_t freeMemory = [[DeviceInfoManager sharedManager] getFreeMemory];
    NSString *freeMemoryInfo = [NSString stringWithFormat:@" %.2f MB == %.2f GB", freeMemory/1024/1024.0, freeMemory/1024/1024/1024.0];
    [self addInfoWithKey:@"空閑的內(nèi)存空間" infoValue:freeMemoryInfo];
    
    // 獲得已使用的內(nèi)存空間
    int64_t usedMemory = [[DeviceInfoManager sharedManager] getUsedMemory];
    NSString *usedMemoryInfo = [NSString stringWithFormat:@" %.2f MB == %.2f GB", usedMemory/1024/1024.0, usedMemory/1024/1024/1024.0];
    [self addInfoWithKey:@"已使用的內(nèi)存空間" infoValue:usedMemoryInfo];
    
    // 獲得正在使用或者很短時(shí)間內(nèi)被使用過(guò)的內(nèi)存
    int64_t activeMemory = [[DeviceInfoManager sharedManager] getActiveMemory];
    NSString *activeMemoryInfo = [NSString stringWithFormat:@"正在使用或者很短時(shí)間內(nèi)被使用過(guò) %.2f MB == %.2f GB", activeMemory/1024/1024.0, activeMemory/1024/1024/1024.0];
    [self addInfoWithKey:@"活躍的內(nèi)存" infoValue:activeMemoryInfo];
    
    // 獲得最近使用過(guò)但是目前處于不活躍狀態(tài)的內(nèi)存
    int64_t inActiveMemory = [[DeviceInfoManager sharedManager] getInActiveMemory];
    NSString *inActiveMemoryInfo = [NSString stringWithFormat:@"但是目前處于不活躍狀態(tài)的內(nèi)存 %.2f MB == %.2f GB", inActiveMemory/1024/1024.0, inActiveMemory/1024/1024/1024.0];
    [self addInfoWithKey:@"最近使用過(guò)" infoValue:inActiveMemoryInfo];
    
    // 獲得用來(lái)存放內(nèi)核和數(shù)據(jù)結(jié)構(gòu)的內(nèi)存
    int64_t wiredMemory = [[DeviceInfoManager sharedManager] getWiredMemory];
    NSString *wiredMemoryInfo = [NSString stringWithFormat:@"framework溜歪、用戶級(jí)別的應(yīng)用無(wú)法分配 %.2f MB == %.2f GB", wiredMemory/1024/1024.0, wiredMemory/1024/1024/1024.0];
    [self addInfoWithKey:@"用來(lái)存放內(nèi)核和數(shù)據(jù)結(jié)構(gòu)的內(nèi)存" infoValue:wiredMemoryInfo];
    
    // 獲得大對(duì)象存放所需的大塊內(nèi)存空間若专,內(nèi)存吃緊自動(dòng)釋放
    int64_t purgableMemory = [[DeviceInfoManager sharedManager] getPurgableMemory];
    NSString *purgableMemoryInfo = [NSString stringWithFormat:@"大對(duì)象存放所需的大塊內(nèi)存空間 %.2f MB == %.2f GB", purgableMemory/1024/1024.0, purgableMemory/1024/1024/1024.0];
    [self addInfoWithKey:@"可釋放的內(nèi)存空間:內(nèi)存吃緊自動(dòng)釋放" infoValue:purgableMemoryInfo];
}

3、獲取磁盤(pán)內(nèi)存信息接口的具體實(shí)現(xiàn)

a蝴猪、獲取磁盤(pán)信息
獲取本 App 所占磁盤(pán)空間
- (NSString *)getApplicationSize
{
    unsigned long long documentSize   =  [self getSizeOfFolder:[self getDocumentPath]];
    unsigned long long librarySize   =  [self getSizeOfFolder:[self getLibraryPath]];
    unsigned long long cacheSize =  [self getSizeOfFolder:[self getCachePath]];
    
    unsigned long long total = documentSize + librarySize + cacheSize;
    
    NSString *applicationSize = [NSByteCountFormatter stringFromByteCount:total countStyle:NSByteCountFormatterCountStyleFile];
    return applicationSize;
}
獲取磁盤(pán)總空間
- (int64_t)getTotalDiskSpace
{
    NSError *error = nil;
    NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
    if (error) return -1;
    
    int64_t space =  [[attrs objectForKey:NSFileSystemSize] longLongValue];
    if (space < 0) space = -1;
    return space;
}
獲取未使用的磁盤(pán)空間
- (int64_t)getFreeDiskSpace
{
    NSError *error = nil;
    NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
    if (error) return -1;
    int64_t space =  [[attrs objectForKey:NSFileSystemFreeSize] longLongValue];
    if (space < 0) space = -1;
    return space;
}
獲取已使用的磁盤(pán)空間
- (int64_t)getUsedDiskSpace
{
    int64_t totalDisk = [self getTotalDiskSpace];
    int64_t freeDisk = [self getFreeDiskSpace];
    if (totalDisk < 0 || freeDisk < 0) return -1;
    
    int64_t usedDisk = totalDisk - freeDisk;
    if (usedDisk < 0) usedDisk = -1;
    return usedDisk;
}

b调衰、獲取內(nèi)存信息
獲取總內(nèi)存空間
- (int64_t)getTotalMemory
{
    int64_t totalMemory = [[NSProcessInfo processInfo] physicalMemory];
    if (totalMemory < -1) totalMemory = -1;
    return totalMemory;
}
獲取活躍的內(nèi)存空間
- (int64_t)getActiveMemory
{
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t page_size;
    vm_statistics_data_t vm_stat;
    kern_return_t kern;
    
    kern = host_page_size(host_port, &page_size);
    if (kern != KERN_SUCCESS) return -1;
    kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    if (kern != KERN_SUCCESS) return -1;
    return vm_stat.active_count * page_size;
}
獲取不活躍的內(nèi)存空間
- (int64_t)getInActiveMemory
{
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t page_size;
    vm_statistics_data_t vm_stat;
    kern_return_t kern;
    
    kern = host_page_size(host_port, &page_size);
    if (kern != KERN_SUCCESS) return -1;
    kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    if (kern != KERN_SUCCESS) return -1;
    return vm_stat.inactive_count * page_size;
}
獲取空閑的內(nèi)存空間
- (int64_t)getFreeMemory
{
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t page_size;
    vm_statistics_data_t vm_stat;
    kern_return_t kern;
    
    kern = host_page_size(host_port, &page_size);
    if (kern != KERN_SUCCESS) return -1;
    kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    if (kern != KERN_SUCCESS) return -1;
    return vm_stat.free_count * page_size;
}
獲取正在使用的內(nèi)存空間
- (int64_t)getUsedMemory
{
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t page_size;
    vm_statistics_data_t vm_stat;
    kern_return_t kern;
    
    kern = host_page_size(host_port, &page_size);
    if (kern != KERN_SUCCESS) return -1;
    kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    if (kern != KERN_SUCCESS) return -1;
    return page_size * (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count);
}
獲取存放內(nèi)核的內(nèi)存空間
- (int64_t)getWiredMemory
{
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t page_size;
    vm_statistics_data_t vm_stat;
    kern_return_t kern;
    
    kern = host_page_size(host_port, &page_size);
    if (kern != KERN_SUCCESS) return -1;
    kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    if (kern != KERN_SUCCESS) return -1;
    return vm_stat.wire_count * page_size;
}
獲取可釋放的內(nèi)存空間
- (int64_t)getPurgableMemory
{
    mach_port_t host_port = mach_host_self();
    mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    vm_size_t page_size;
    vm_statistics_data_t vm_stat;
    kern_return_t kern;
    
    kern = host_page_size(host_port, &page_size);
    if (kern != KERN_SUCCESS) return -1;
    kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
    if (kern != KERN_SUCCESS) return -1;
    return vm_stat.purgeable_count * page_size;
}

c、獲取文件路徑
DocumentPath
- (NSString *)getDocumentPath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = [paths firstObject];
    return basePath;
}
LibraryPath
- (NSString *)getLibraryPath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *basePath = [paths firstObject];
    return basePath;
}
CachePath
- (NSString *)getCachePath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *basePath = [paths firstObject];
    return basePath;
}

d自阱、獲取目錄中所有文件的大小和
- (unsigned long long)getSizeOfFolder:(NSString *)folderPath
{
    NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:nil];
    NSEnumerator *contentsEnumurator = [contents objectEnumerator];
    
    NSString *file;
    unsigned long long folderSize = 0;
    
    while (file = [contentsEnumurator nextObject])
    {
        NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:file] error:nil];
        folderSize += [[fileAttributes objectForKey:NSFileSize] intValue];
    }
    return folderSize;
}

五嚎莉、CPU信息

1、真機(jī)運(yùn)行在控制臺(tái)輸出結(jié)果

2020-09-07 17:38:08.723640+0800 DeviceInfoDemo[4720:822749] infoKey:CPU 處理器名稱---infoValue:A12 Bionic
2020-09-07 17:38:08.723983+0800 DeviceInfoDemo[4720:822749] infoKey:CPU總數(shù)目---infoValue:6
2020-09-07 17:38:08.724229+0800 DeviceInfoDemo[4720:822749] infoKey:CPU使用的總比例---infoValue:1.025270104408264
2020-09-07 17:38:08.724328+0800 DeviceInfoDemo[4720:822749] infoKey:CPU 頻率---infoValue:1
2020-09-07 17:38:08.724492+0800 DeviceInfoDemo[4720:822749] infoKey:單個(gè)CPU使用比例---infoValue:0.05<-->0.27<-->0.21<-->0.05<-->0.19<-->0.25

2沛豌、能夠獲取到的CPU信息

a趋箩、工具類提供的獲取磁盤(pán)內(nèi)存信息的接口
/** 獲取CPU處理器名稱 */
- (NSString *)getCPUProcessor;
/** 獲取CPU數(shù)量 */
- (NSUInteger)getCPUCount;
/** 獲取CPU總的使用百分比 */
- (float)getCPUUsage;
/** 獲取單個(gè)CPU使用百分比 */
- (NSArray *)getPerCPUUsage;
/** 獲取CPU頻率 */
- (NSUInteger)getCPUFrequency;

b赃额、調(diào)用接口獲取信息
- (void)setupCPUInfo
{
    // 獲取CPU處理器名稱
    NSString *cpuName = [[DeviceInfoManager sharedManager] getCPUProcessor];
    [self addInfoWithKey:@"CPU 處理器名稱" infoValue:cpuName];
    
    // 獲取CPU總數(shù)目
    NSUInteger cpuCount = [[DeviceInfoManager sharedManager] getCPUCount];
    [self addInfoWithKey:@"CPU總數(shù)目" infoValue:@(cpuCount)];
    
    // 獲取CPU使用的總比例
    CGFloat cpuUsage = [[DeviceInfoManager sharedManager] getCPUUsage];
    [self addInfoWithKey:@"CPU使用的總比例" infoValue:@(cpuUsage)];
    
    // 獲取CPU 頻率
    NSUInteger cpuFrequency = [[DeviceInfoManager sharedManager] getCPUFrequency];
    [self addInfoWithKey:@"CPU 頻率" infoValue:@(cpuFrequency)];
    
    // 獲取單個(gè)CPU使用比例
    NSArray *perCPUArr = [[DeviceInfoManager sharedManager] getPerCPUUsage];
    NSMutableString *perCPUUsage = [NSMutableString string];
    for (NSNumber *per in perCPUArr)
    {
        [perCPUUsage appendFormat:@"%.2f<-->", per.floatValue];
    }
    [self addInfoWithKey:@"單個(gè)CPU使用比例" infoValue:perCPUUsage];
}

3、獲取CPU信息接口的具體實(shí)現(xiàn)

a叫确、獲取CPU處理器名稱
- (NSString *)getCPUProcessor
{
    return [[DeviceDataLibrery sharedLibrery] getCPUProcessor] ? : @"unKnown";
}
- (const NSString *)getCPUProcessor
{
    return CPUNameContainer[self.device];
}

b跳芳、獲取CPU數(shù)量
- (NSUInteger)getCPUCount
{
    return [NSProcessInfo processInfo].activeProcessorCount;
}

c、獲取CPU頻率
- (NSUInteger)getCPUFrequency
{
    return [self getSystemInfo:HW_CPU_FREQ];
}

d竹勉、獲取單個(gè)CPU使用百分比
- (NSArray *)getPerCPUUsage
{
    processor_info_array_t _cpuInfo, _prevCPUInfo = nil;
    mach_msg_type_number_t _numCPUInfo, _numPrevCPUInfo = 0;
    unsigned _numCPUs;
    NSLock *_cpuUsageLock;
    
    int _mib[2U] = { CTL_HW, HW_NCPU };
    size_t _sizeOfNumCPUs = sizeof(_numCPUs);
    int _status = sysctl(_mib, 2U, &_numCPUs, &_sizeOfNumCPUs, NULL, 0U);
    if (_status)
        _numCPUs = 1;
    
    _cpuUsageLock = [[NSLock alloc] init];
    
    natural_t _numCPUsU = 0U;
    kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &_numCPUsU, &_cpuInfo, &_numCPUInfo);
    if (err == KERN_SUCCESS)
    {
        [_cpuUsageLock lock];
        
        NSMutableArray *cpus = [NSMutableArray new];
        for (unsigned i = 0U; i < _numCPUs; ++i)
        {
            Float32 _inUse, _total;
            if (_prevCPUInfo)
            {
                _inUse = (
                          (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER]   - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER])
                          + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM])
                          + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE]   - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE])
                          );
                _total = _inUse + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]);
            }
            else
            {
                _inUse = _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE];
                _total = _inUse + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE];
            }
            [cpus addObject:@(_inUse / _total)];
        }
        
        [_cpuUsageLock unlock];
        if (_prevCPUInfo)
        {
            size_t prevCpuInfoSize = sizeof(integer_t) * _numPrevCPUInfo;
            vm_deallocate(mach_task_self(), (vm_address_t)_prevCPUInfo, prevCpuInfoSize);
        }
        return cpus;
    }
    else
    {
        return nil;
    }
}

e飞盆、獲取CPU總的使用百分比
- (float)getCPUUsage
{
    float cpu = 0;
    NSArray *cpus = [self getPerCPUUsage];
    if (cpus.count == 0) return -1;
    for (NSNumber *n in cpus)
    {
        cpu += n.floatValue;
    }
    return cpu;
}

六、網(wǎng)絡(luò)信息

1次乓、概念解釋

廣告位標(biāo)識(shí)符:在同一個(gè)設(shè)備上的所有App都會(huì)取到相同的值吓歇,是蘋(píng)果專門(mén)給各廣告提供商用來(lái)追蹤用戶而設(shè)的,用戶可以在設(shè)置|隱私|廣告追蹤里重置此id的值票腰,或限制此id的使用城看,故此id有可能會(huì)取不到值,但好在Apple默認(rèn)是允許追蹤的丧慈,而且一般用戶都不知道有這么個(gè)設(shè)置析命,所以基本上用來(lái)監(jiān)測(cè)推廣效果主卫,是戳戳有余了逃默。

UUID:Universally Unique Identifier的縮寫(xiě),中文意思是通用唯一識(shí)別碼簇搅。它是讓分布式系統(tǒng)中的所有元素完域,都能有唯一的辨識(shí)資訊,而不需要透過(guò)中央控制端來(lái)做辨識(shí)資訊的指定瘩将。這樣吟税,每個(gè)人都可以建立不與其它人沖突的 UUID。在此情況下姿现,就不需考慮數(shù)據(jù)庫(kù)建立時(shí)的名稱重復(fù)問(wèn)題肠仪。蘋(píng)果公司建議使用UUID為應(yīng)用生成唯一標(biāo)識(shí)字符串。


2备典、真機(jī)運(yùn)行效果

a异旧、控制臺(tái)輸出結(jié)果
2020-09-07 17:03:55.340667+0800 DeviceInfoDemo[4683:810709] infoKey:廣告位標(biāo)識(shí)符idfa:---infoValue:5BE8FE64-29FC-40C6-9EB1-36B2B5F65ECB
2020-09-07 17:03:55.341933+0800 DeviceInfoDemo[4683:810709] infoKey:唯一識(shí)別碼uuid---infoValue:A4997507-9A41-4CFC-A9ED-25FB96B6AE51
2020-09-07 17:03:55.342129+0800 DeviceInfoDemo[4683:810709] infoKey:device_token_crc32真機(jī)測(cè)試才會(huì)顯示---infoValue:
2020-09-07 17:03:55.342558+0800 DeviceInfoDemo[4683:810709] infoKey:macAddress---infoValue:020000000000
2020-09-07 17:03:55.342975+0800 DeviceInfoDemo[4683:810709] infoKey:deviceIP---infoValue:169.254.215.144
2020-09-07 17:03:55.343368+0800 DeviceInfoDemo[4683:810709] infoKey:蜂窩地址---infoValue:172.25.39.187
2020-09-07 17:03:55.343775+0800 DeviceInfoDemo[4683:810709] infoKey:WIFI IP地址---infoValue:fe80::14f5:22a1:b6df:3ead

b、APP顯示的信息
獲取IP地址

3提佣、能夠獲取到的網(wǎng)絡(luò)信息

a吮蛹、工具類提供的獲取網(wǎng)絡(luò)信息的接口
/** 獲取廣告標(biāo)識(shí)符 */
- (NSString *)getIDFA;
/** 獲取mac地址 */
- (NSString *)getMacAddress;
/** 獲取ip地址 */
- (NSString *)getDeviceIPAddresses;
/** 獲取WIFI IP地址 */
- (NSString *)getIpAddressWIFI;
/** 獲取蜂窩地址 */
- (NSString *)getIpAddressCell;

b、調(diào)用接口獲取信息
- (void)setupAddressInfo
{
    // 獲取廣告位標(biāo)識(shí)符
    NSString *idfa = [[DeviceInfoManager sharedManager] getIDFA];
    [self addInfoWithKey:@"廣告位標(biāo)識(shí)符idfa:" infoValue:idfa];
    
    // 獲取UUID
    NSString *uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    [self addInfoWithKey:@"唯一識(shí)別碼uuid" infoValue:uuid];
    
    // 這個(gè) 拌屏!還存在問(wèn)題
    NSString *device_token_crc32 = [[NSUserDefaults standardUserDefaults] objectForKey:@"device_token_crc32"] ? : @"";
    [self addInfoWithKey:@"device_token_crc32真機(jī)測(cè)試才會(huì)顯示" infoValue:device_token_crc32];

    // 獲取mac地址
    NSString *macAddress = [[DeviceInfoManager sharedManager] getMacAddress];
    [self addInfoWithKey:@"macAddress" infoValue:macAddress];
    
    // 獲取設(shè)備的IP地址
    NSString *deviceIP = [[NetWorkInfoManager sharedManager] getDeviceIPAddresses];
    [self addInfoWithKey:@"deviceIP" infoValue:deviceIP];
    
    // 獲取蜂窩地址
    NSString *cellIP = [[NetWorkInfoManager sharedManager] getIpAddressCell];
    [self addInfoWithKey:@"蜂窩地址" infoValue:cellIP];
    
    // 獲取WIFI IP地址
    NSString *wifiIP = [[NetWorkInfoManager sharedManager] getIpAddressWIFI];
    [self addInfoWithKey:@"WIFI IP地址" infoValue:wifiIP];
}

4潮针、獲取網(wǎng)絡(luò)信息接口的具體實(shí)現(xiàn)

a、需要引入的頭文件
#import "NSData+CRC32.h"

// 獲取ip需要的頭文件
#include <ifaddrs.h>
#include <sys/socket.h> // Per msqr
#import <sys/ioctl.h>
#include <net/if.h>
#import <arpa/inet.h>

b倚喂、獲取廣告標(biāo)識(shí)符
- (NSString *)getIDFA
{
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}

c每篷、獲取mac地址
- (NSString *)getMacAddress
{
    int mib[6];
    size_t len;
    char *buf;
    unsigned char *ptr;
    struct if_msghdr *ifm;
    struct sockaddr_dl *sdl;
    
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    
    if ((mib[5] = if_nametoindex("en0")) == 0)
    {
        printf("Error: if_nametoindex error/n");
        return NULL;
    }
    
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
    {
        printf("Error: sysctl, take 1/n");
        return NULL;
    }
    
    if ((buf = malloc(len)) == NULL)
    {
        printf("Could not allocate memory. error!/n");
        return NULL;
    }
    
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
    {
        printf("Error: sysctl, take 2");
        return NULL;
    }
    
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    
    NSString *outstring = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    
    return [outstring uppercaseString];
}

d、獲取ip地址
- (NSString *)getDeviceIPAddresses
{
    
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    
    NSMutableArray *ips = [NSMutableArray array];
    
    int BUFFERSIZE = 4096;
    
    struct ifconf ifc;
    
    char buffer[BUFFERSIZE], *ptr, lastname[IFNAMSIZ], *cptr;
    
    struct ifreq *ifr, ifrcopy;
    
    ifc.ifc_len = BUFFERSIZE;
    ifc.ifc_buf = buffer;
    
    if (ioctl(sockfd, SIOCGIFCONF, &ifc) >= 0)
    {
        
        for (ptr = buffer; ptr < buffer + ifc.ifc_len; )
        {
            
            ifr = (struct ifreq *)ptr;
            int len = sizeof(struct sockaddr);
            
            if (ifr->ifr_addr.sa_len > len)
            {
                len = ifr->ifr_addr.sa_len;
            }
            
            ptr += sizeof(ifr->ifr_name) + len;
            if (ifr->ifr_addr.sa_family != AF_INET) continue;
            if ((cptr = (char *)strchr(ifr->ifr_name, ':')) != NULL) *cptr = 0;
            if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) continue;
            
            memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
            ifrcopy = *ifr;
            ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
            
            if ((ifrcopy.ifr_flags & IFF_UP) == 0) continue;
            
            NSString *ip = [NSString  stringWithFormat:@"%s", inet_ntoa(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr)];
            [ips addObject:ip];
        }
    }
    
    close(sockfd);
    NSString *deviceIP = @"";
    
    for (int i=0; i < ips.count; I++)
    {
        if (ips.count > 0)
        {
            deviceIP = [NSString stringWithFormat:@"%@",ips.lastObject];
        }
    }
    return deviceIP;
}

e、獲取WIFI IP地址
- (NSString *)getIpAddressWIFI
{
    return [self ipAddressWithIfaName:@"en0"];
}

f焦读、獲取蜂窩地址
- (NSString *)getIpAddressCell
{
    return [self ipAddressWithIfaName:@"pdp_ip0"];
}

g带兜、獲取網(wǎng)絡(luò)地址
- (NSString *)ipAddressWithIfaName:(NSString *)name
{
    if (name.length == 0) return nil;
    NSString *address = nil;
    struct ifaddrs *addrs = NULL;
    
    if (getifaddrs(&addrs) == 0)
    {
        struct ifaddrs *addr = addrs;
        while (addr)
        {
            if ([[NSString stringWithUTF8String:addr->ifa_name] isEqualToString:name])
            {
                sa_family_t family = addr->ifa_addr->sa_family;
                switch (family)
                {
                    case AF_INET:// IPv4
                    {
                        char str[INET_ADDRSTRLEN] = {0};
                        inet_ntop(family, &(((struct sockaddr_in *)addr->ifa_addr)->sin_addr), str, sizeof(str));
                        if (strlen(str) > 0)
                        {
                            address = [NSString stringWithUTF8String:str];
                        }
                    } break;
                        
                    case AF_INET6:// IPv6
                    {
                        char str[INET6_ADDRSTRLEN] = {0};
                        inet_ntop(family, &(((struct sockaddr_in6 *)addr->ifa_addr)->sin6_addr), str, sizeof(str));
                        if (strlen(str) > 0)
                        {
                            address = [NSString stringWithUTF8String:str];
                        }
                    }
                    default: break;
                }
                if (address) break;
            }
            addr = addr->ifa_next;
        }
    }
    freeifaddrs(addrs);
    return address ? address : @"該設(shè)備不存在該ip地址";
}

5、判斷IPv4和IPv6并獲取地址

a吨灭、需要用到以下文件和宏
// 需要用到以下文件
# import <ifaddrs.h>
# import <arpa/inet.h>
# import <net/if.h>

// 宏
#define IOS_CELLULAR    @"pdp_ip0"
#define IOS_WIFI        @"en0"
#define IOS_VPN         @"utun0"
#define IP_ADDR_IPv4    @"ipv4"
#define IP_ADDR_IPv6    @"ipv6"

// 框架
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <SystemConfiguration/SCNetworkReachability.h>

b刚照、獲取到硬件設(shè)備的各個(gè)IP
+(NSDictionary *)getDeviceIPAddresses
{
    NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
    // retrieve the current interfaces - returns 0 on succes
    struct ifaddrs *interfaces;
    if(!getifaddrs(&interfaces))
    {
        // Loop through linked list of interfaces
        struct ifaddrs *interface;
        for(interface = interfaces; interface; interface = interface->ifa_next)
        {
            // deeply nested code harder to read
            if(!(interface->ifa_flags & IFF_UP))
            {
                continue;
            }
            const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
            char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
            if(addr && (addr->sin_family == AF_INET || addr->sin_family == AF_INET6))
            {
                NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
                NSString *type;
                if(addr->sin_family == AF_INET)
                {
                    if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN))
                    {
                        type = IP_ADDR_IPv4;
                    }
                }
                else
                {
                    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
                    if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN))
                    {
                        type = IP_ADDR_IPv6;
                    }
                }
                if(type)
                {
                    NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                    addresses[key] = [NSString stringWithUTF8String:addrBuf];
                }
            }
        }
        // Free memory
        freeifaddrs(interfaces);
    }
    return [addresses count] ? addresses : nil;
}

c、把拿到的地址打印一下 喧兄,會(huì)看到各種不同的地址无畔,如pdp_ip0/ipv4,en0/ipv4吠冤,en0/ipv6 等
2020-07-29 14:09:47.782043+0800 Demo[88428:24193761] addresses: {
    "awdl0/ipv6" = "fe80::a8a9:aff:fef2:3196";
    "en0/ipv4" = "10.130.11.159";
    "en0/ipv6" = "fe80::1049:1471:c55e:6a1d";
    "en1/ipv4" = "10.130.168.169";
    "en1/ipv6" = "fe80::c59:8913:4837:6f5e";
    "en5/ipv4" = "169.254.62.42";
    "en5/ipv6" = "fe80::c17:b446:86c9:2269";
    "llw0/ipv6" = "fe80::a8a9:aff:fef2:3196";
    "lo0/ipv4" = "127.0.0.1";
    "lo0/ipv6" = "fe80::1";
    "utun0/ipv6" = "fe80::cfd6:352a:e0a:561d";
    "utun1/ipv6" = "fe80::9b18:e1e0:3e6a:2b25";
    "utun2/ipv6" = "fe80::3660:5e7:7b88:748c";
    "utun3/ipv6" = "fe80::93ac:7e8b:9b5d:1208";
    "utun4/ipv6" = "fe80::ec2a:d9b2:b54:1941";
    "utun5/ipv6" = "fe80::a033:c7cf:1848:d69c";
    "utun6/ipv6" = "fe80::d1bf:ed25:ef85:9880";
    "utun7/ipv6" = "fe80::e82b:d4de:202b:79bb";
    "utun8/ipv6" = "fe80::4043:b856:1f83:3b0e";
    "utun9/ipv6" = "fe80::95b4:12c8:e493:397a";
}

顧名思義這就是不同網(wǎng)絡(luò)環(huán)境下的IPv4 浑彰、IPv6地址,其中我們需要用到下面這幾個(gè)拯辙。其他的當(dāng)然也有用郭变,比如打開(kāi)熱點(diǎn)之后的也能在里面找到。

#define IOS_CELLULAR    @"pdp_ip0" // 蜂窩網(wǎng)絡(luò)
#define IOS_WIFI        @"en0" // WiFi網(wǎng)絡(luò)
#define IOS_VPN         @"utun0" // VPN

#define IP_ADDR_IPv4    @"ipv4"
#define IP_ADDR_IPv6    @"ipv6"

d涯保、判斷是否支持IPv6

拿到地址之后判斷我們常用的這三個(gè)地址中有沒(méi)有IPv6的可用地址诉濒,因?yàn)橛貌煌O(shè)備多獲取幾次地址,你就會(huì)發(fā)現(xiàn)其中有不可用地址夕春,比如IPv4127.0.0.1未荒、169.254.120.241IPv6中 以fe80開(kāi)頭的地址及志。所以 片排,如果地址中有可用的IPv6那就說(shuō)明當(dāng)前設(shè)備的網(wǎng)絡(luò)環(huán)境支持IPv6。接下來(lái)我們就按照這個(gè)規(guī)則來(lái)判斷是否支持IPv6速侈。

+(BOOL)isSupportIpv6
{
    NSArray *searchArray =
    @[ IOS_VPN @"/" IP_ADDR_IPv6,
       IOS_VPN @"/" IP_ADDR_IPv4,
       IOS_WIFI @"/" IP_ADDR_IPv6,
       IOS_WIFI @"/" IP_ADDR_IPv4,
       IOS_CELLULAR @"/" IP_ADDR_IPv6,
       IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;
    
    NSDictionary *addresses = [self getDeviceIPAddresses];
    NSLog(@"addresses: %@", addresses);
    
    __block BOOL isSupportIpv6 = NO;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
        NSLog(@"key: %@---addresses[key]: %@",key, addresses[key] );
        
        if ([key rangeOfString:@"ipv6"].length > 0  && ![[NSString stringWithFormat:@"%@",addresses[key]] hasPrefix:@"(null)"] )
        {
            if (![addresses[key] hasPrefix:@"fe80"])
            {
                isSupportIpv6 = YES;
            }
        }
    }];
    return isSupportIpv6;
}

輸出結(jié)果為:

2020-07-29 14:17:51.637787+0800 Demo[88453:24198960] key: utun0/ipv6---addresses[key]: fe80::cfd6:352a:e0a:561d
2020-07-29 14:17:51.638453+0800 Demo[88453:24198960] key: utun0/ipv4---addresses[key]: (null)
2020-07-29 14:17:51.638522+0800 Demo[88453:24198960] key: en0/ipv6---addresses[key]: fe80::1049:1471:c55e:6a1d
2020-07-29 14:17:51.638593+0800 Demo[88453:24198960] key: en0/ipv4---addresses[key]: 10.130.11.159
2020-07-29 14:17:51.638657+0800 Demo[88453:24198960] key: pdp_ip0/ipv6---addresses[key]: (null)
2020-07-29 14:17:51.638723+0800 Demo[88453:24198960] key: pdp_ip0/ipv4---addresses[key]: (null)

e率寡、獲取IP地址

已經(jīng)判斷好IPv6了,然后該取IP地址了倚搬。這個(gè)時(shí)候因?yàn)橛?code>IPv6存在的原因冶共,所以獲取地址也需要區(qū)分一下。

+ (NSString *)getNetworkIPAddress
{
    NSArray *searchArray = [self isSupportIpv6] ?
    @[ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] :
    @[ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] ;
    
    NSDictionary *addresses = [self getIPAddresses];
    
    __block NSString *address;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
     {
        address = addresses[key];
        if([self isValidatIP:address])
        {
            *stop = YES;
        }
    }];
    NSLog(@"IPAddress: %@", address);
    return address ? address : @"0.0.0.0";
}

看到這個(gè)地方潭枣,肯定有人有疑問(wèn)了比默,為啥這個(gè)取值的數(shù)組searchArray里面還是包含有IPv4IPv6?可以看到IPv4IPv6的順序是不一樣的盆犁, 我的理解是這個(gè)地方的設(shè)備訪問(wèn)肯定是有順序的命咐,比如我蜂窩網(wǎng)絡(luò)雖然支持IPv6,但是我現(xiàn)在連上了WiFi谐岁,這個(gè)WiFiIPv4的醋奠,那設(shè)備肯定是優(yōu)先使用WiFi進(jìn)行網(wǎng)絡(luò)訪問(wèn)榛臼。


f、如何判斷一個(gè)字符串是不是 IP 地址呢

IPv4的特點(diǎn)入手:由4段數(shù)字組成窜司,其中有三個(gè)'.'符號(hào)沛善,每個(gè)數(shù)字的范圍都在0~255之間,且每個(gè)數(shù)都是合法的數(shù)字(前面沒(méi)有零)塞祈。所以我們可以先把這個(gè)字符串用‘.'分隔開(kāi)金刁,再統(tǒng)計(jì)一下'.'的個(gè)數(shù),最后判斷每個(gè)數(shù)字是否合法即可议薪。判斷IPv6的思路和IPv4類似尤蛮,拆分并且判斷分隔符的個(gè)數(shù),依次檢查每個(gè)數(shù)的正確性斯议,區(qū)別是IPv6的地址不需要判斷前導(dǎo)零产捞,但是需要注意大小寫(xiě)都是合法的。

實(shí)現(xiàn)方案一:正則表達(dá)式
+ (BOOL)isText:(NSString *)text pattern:(NSString *)pattern
{
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",pattern];
    return [predicate evaluateWithObject:text];
}
/**
 * 判斷字符串是否為IP地址
 * param iPAddress IP地址字符串
 * return BOOL 是返回YES哼御,否返回NO
 */
+ (BOOL)isIPAddress:(NSString *)iPAddress
{
    NSString *pattern = @"^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$";
    return [self isText:iPAddress pattern:pattern];
}
實(shí)現(xiàn)方案二:數(shù)字范圍
+ (BOOL)isValidIP:(NSString *)ipStr
{
    if (nil == ipStr)
    {
        return NO;
    }
    
    NSArray *ipArray = [ipStr componentsSeparatedByString:@"."];
    if (ipArray.count == 4)
    {
        for (NSString *ipnumberStr in ipArray)
        {
            int ipnumber = [ipnumberStr intValue];
            if (!(ipnumber>=0 && ipnumber<=255))
            {
                return NO;
            }
        }
        return YES;
    }
    return NO;
}

以下是在模擬器在不支持IPv6的情況下獲得的結(jié)果坯临。

2020-07-29 14:17:51.640431+0800 Demo[88453:24198960] IPAddress: 10.130.11.159
2020-07-29 14:17:51.640534+0800 Demo[88453:24198960] IP地址為:10.130.11.159

Demo

Demo在我的Github上,歡迎下載恋昼。
BasicsDemo

參考文獻(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載看靠,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。
  • 序言:七十年代末焰雕,一起剝皮案震驚了整個(gè)濱河市衷笋,隨后出現(xiàn)的幾起案子芳杏,更是在濱河造成了極大的恐慌矩屁,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爵赵,死亡現(xiàn)場(chǎng)離奇詭異吝秕,居然都是意外死亡商佛,警方通過(guò)查閱死者的電腦和手機(jī)救巷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)郊尝,“玉大人秕铛,你說(shuō)我怎么就攤上這事约郁。” “怎么了但两?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵鬓梅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谨湘,道長(zhǎng)绽快,這世上最難降的妖魔是什么芥丧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮坊罢,結(jié)果婚禮上续担,老公的妹妹穿的比我還像新娘。我一直安慰自己活孩,他們只是感情好物遇,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著憾儒,像睡著了一般挎挖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上航夺,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天蕉朵,我揣著相機(jī)與錄音,去河邊找鬼阳掐。 笑死始衅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缭保。 我是一名探鬼主播汛闸,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼艺骂!你這毒婦竟也來(lái)了诸老?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钳恕,失蹤者是張志新(化名)和其女友劉穎别伏,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體忧额,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厘肮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了睦番。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片类茂。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖托嚣,靈堂內(nèi)的尸體忽然破棺而出巩检,到底是詐尸還是另有隱情,我是刑警寧澤示启,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布兢哭,位于F島的核電站,受9級(jí)特大地震影響丑搔,放射性物質(zhì)發(fā)生泄漏厦瓢。R本人自食惡果不足惜提揍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望煮仇。 院中可真熱鬧劳跃,春花似錦、人聲如沸浙垫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)夹姥。三九已至杉武,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辙售,已是汗流浹背轻抱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旦部,地道東北人祈搜。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像士八,于是被迫代替她去往敵國(guó)和親容燕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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