原創(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)用
知道app
的URL Schemes
可以使用openUrl
來(lái)獲取iOS
是否安裝了某款軟件,比如這樣[[UIApplication sharedApplication] canOpenURL:@"damon://"]
你辣,會(huì)返回一個(gè)bool
值巡通,為true
則安裝了,否則沒(méi)有安裝舍哄。
獲取app的url schemes
把相應(yīng)的app
的ipa
安裝文件下載下來(lái)宴凉,把文件 .ipa
的后綴改成.zip
,然后解壓表悬,打開(kāi) Payload/xxx.app/Info.plist
這個(gè)文件弥锄,找到 URL types
下的URL Schemes
下的數(shù)組對(duì)應(yīng)的值就是這個(gè) app
的 URL 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-B
的URL Schemes
為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
增加LSApplicationQueriesSchemes
(array
類型),把要跳轉(zhuǎn)的app的UrlScheme
加進(jìn)去菇绵。
運(yùn)行效果如下:
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è)界面WriterViewController
和WasteMaterialsViewController
翅雏。
步驟二:在應(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)行效果如下:
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-B
的URL Schemes
;WriterViewController
是用來(lái)區(qū)別跳轉(zhuǎn)頁(yè)面的標(biāo)識(shí)剃袍;? 是分割符黄刚;AppA
是跳轉(zhuǎn)回的應(yīng)用App-A
的URL 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-A
的URL 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?AppA
、AppB://WasteMaterialsViewController?AppA
根欧。
步驟四:在將要跳轉(zhuǎn)的頁(yè)面控制器WasteMaterialsViewController
和WriterViewController
中定義一個(gè)屬性@property (nonatomic, copy) NSString *urlString;
怜珍,用于接受、截取出跳轉(zhuǎn)回的應(yīng)用(即App-A
)的URL Schemes
凤粗,執(zhí)行跳轉(zhuǎn)酥泛。
步驟五:在App-B
的AppDelegate
中傳遞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)行效果如下:
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;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顯示的信息
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顯示的信息
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顯示的信息
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顯示的信息
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)其中有不可用地址夕春,比如IPv4
中 127.0.0.1
未荒、169.254.120.241
,IPv6
中 以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
里面還是包含有IPv4
和IPv6
?可以看到IPv4
和IPv6
的順序是不一樣的盆犁, 我的理解是這個(gè)地方的設(shè)備訪問(wèn)肯定是有順序的命咐,比如我蜂窩網(wǎng)絡(luò)雖然支持IPv6
,但是我現(xiàn)在連上了WiFi
谐岁,這個(gè)WiFi
是IPv4
的醋奠,那設(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