iPhone/iOS開啟個人熱點的縱向適配小結

作者:弦苦
地址:http://blog.csdn.net/phunxm/article/details/42967035

一.iPhone創建個人熱點

iPhone/iOS雙環上網,即iPhone通過創建個人熱點(Personal Hotspot)做到共享上網,支持便攜式Wi-Fi熱點、藍牙共享網路和USB共享網路。

1.若iPhone已開啟了WiFi(和藍牙),則直接創建成功。

其他設備可通過WiFi(或藍牙)搜尋熱點名稱並連接做到共享上網。

需要說明的是:蘋果的藍牙協議是封閉的,只支持蘋果的設備(iPhone/iPad/iMac)間連接,無法與Android等設備的藍牙進行發現配對!

2.若iPhone只開啟了藍牙,未開啟WiFi,則提示

若選擇【打開」Wi-Fi」】(Turn on Wi-Fi),則其他設備可通過WiFi搜尋熱點名稱並連接做到共享上網。

若選擇【僅藍牙和USB】(Bluetooth and USB Only),則其他設備可通過藍牙或USB連接到該iPhone搜尋熱點名稱並連接做到共享上網。

3.若iPhone未開啟藍牙和WiFi,則提示

若選擇【打開」Wi-Fi」和藍牙】(Turn on Wi-Fi and Bluetooth),則其他設備可通過藍牙/WiFi搜尋熱點名稱並連接做到共享上網。

若選擇【僅USB】(USB Only),則其他設備可通過USB連接到該iPhone搜尋熱點名稱並連接做到共享上網。

二.iMac通過USB連接iPhone共享個人熱點上網

當iPhone新建了個人熱點,iMac(Mac OS X)通過USB連接上iPhone時,將自動連接上iPhone的個人熱點(the first 1 Connection)。

在Mac/Xcode上調試iPhone真機時,若只想調試iPhone/Android連接個人熱點的情形(以便測試有熱點欄和無熱點欄的情況),則可在Network Preferences中刪除iPhone USB接口(interface),防止Mac自動通過USB連接上iPhone熱點對調試造成干擾。

三.iPhone/iOS個人熱點狀態欄

iPhone作為個人熱點且有連接時,系統狀態欄下面會多一行熱點連接提示欄」Personal Hotspot: * Connection」,縱向會下壓20pt;當所有連接都斷開時,熱點欄消失,縱向高度恢復正常。

1.系統狀態欄

APP_STATUSBAR_HEIGHT=[UIApplication sharedApplication].statusBarFrame.size.height,包含熱點欄(如有)高度,標準高度為20pt,當有個人熱點連接時,高度為40pt。

// iOS系統版本

#define SYSTEM_VERSION    [[[UIDevice currentDevice] systemVersion] doubleValue]

// 標準系統狀態欄高度
#define SYS_STATUSBAR_HEIGHT                        20
// 熱點欄高度
#define HOTSPOT_STATUSBAR_HEIGHT            20
// 導航欄(UINavigationController.UINavigationBar)高度
#define NAVIGATIONBAR_HEIGHT                44
// 工具欄(UINavigationController.UIToolbar)高度
#define TOOLBAR_HEIGHT                              44
// 標籤欄(UITabBarController.UITabBar)高度
#define TABBAR_HEIGHT                              44
// APP_STATUSBAR_HEIGHT=SYS_STATUSBAR_HEIGHT+[HOTSPOT_STATUSBAR_HEIGHT]
#define APP_STATUSBAR_HEIGHT                (CGRectGetHeight([UIApplication sharedApplication].statusBarFrame))
// 根據APP_STATUSBAR_HEIGHT判斷是否存在熱點欄
#define IS_HOTSPOT_CONNECTED                (APP_STATUSBAR_HEIGHT==(SYS_STATUSBAR_HEIGHT+HOTSPOT_STATUSBAR_HEIGHT)?YES:NO)
// 無熱點欄時,標準系統狀態欄高度+導航欄高度
#define NORMAL_STATUS_AND_NAV_BAR_HEIGHT    (SYS_STATUSBAR_HEIGHT+NAVIGATIONBAR_HEIGHT)
// 實時系統狀態欄高度+導航欄高度,如有熱點欄,其高度包含在APP_STATUSBAR_HEIGHT中。
#define STATUS_AND_NAV_BAR_HEIGHT                    (APP_STATUSBAR_HEIGHT+NAVIGATIONBAR_HEIGHT)

2.UIViewController.view.bounds.height

  • SYSTEM_VERSION < 7.0,UIViewController.view.bounds.height包含導航欄高度,不包含系統狀態欄高度,也不包含熱點欄(如果有)。

  • SYSTEM_VERSION ≥ 7.0,UIViewController.view.bounds.height包含標準系統狀態欄高度和導航欄高度,但不包含熱點欄(如果有)。

也即當有熱點欄時,UIViewController.view.bounds.height都自動扣除了熱點欄的高度,iOS<7.0不包含標準系統狀態欄,iOS≥7.0包含標準系統狀態欄。

由於iOS7把整個螢幕高度(包括狀態欄,不包括熱點欄)都作為了視圖控制器的有效高度,因此從iOS6升級到iOS7時,會出現視圖整體上移了一個狀態欄的高度(20pt),並和上層的狀態欄交疊在一起。

解決方法:設置extendedLayoutIncludesOpaqueBars屬性為NO,設置edgesForExtendedLayout為UIRectEdgeNone。

3.UIViewController適應熱點欄示例代碼

// MyViewController接口繼承自UIViewController
@interface MyViewController : UIViewController

// MyViewController* myViewController入棧
MyViewController* myViewController = [[MyViewController alloc] init];
[self.navigationController pushViewController:myViewController animated:YES];

- (id)init

{

    // ...


    // 初始非全屏
    _bFullScreen = NO;
    // 進入該UIViewController之前的狀態
    _lastStatusBarStyle = [[UIApplication sharedApplication] statusBarStyle];

    _lastBarTranslucent = self.navigationController.navigationBar.translucent;


    // ...
}


// 排版時,注意logical coordinate space和device coordinate space的區別,注意frame和bounds的區別!

- (void)loadView

{

    // ...


    // 計算Custom Content View的Rect
    if (!_supportFullScreen)
    {
        CGFloat contentSatrtY = 0;

        if (IS_HOTSPOT_CONNECTED) { // iPhone4(s)-iOS6/iOS7螢幕坐標系下:hostView.frame={{0, 40}, {320, 440}}/{{0, 20}, {320, 460}}
            contentSatrtY = STATUS_AND_NAV_BAR_HEIGHT; // 84
            if (SYSTEM_VERSION >= 7.0) { // 如果設置了edgesForExtendedLayout=UIRectEdgeNone
                contentSatrtY -= HOTSPOT_STATUSBAR_HEIGHT;// 64(有熱點欄時,會自動下移20)
            }
        } else { // iPhone4(s)-iOS6/iOS7螢幕坐標系下:hostView.frame={{0, 20}, {320, 460}}/{{0, 0}, {320, 480}}
            contentSatrtY = NORMAL_STATUS_AND_NAV_BAR_HEIGHT; // 64
        }

        // contentSatrtY基於UIViewController.view所在的螢幕坐標系進行排版
        contentRect = CGRectMake(0, contentSatrtY, hostView.width, SCREEN_HEIGHT-STATUS_AND_NAV_BAR_HEIGHT-TOOLBAR_HEIGHT);
    }
    else // 針對iOS6/7分別配置了wantsFullScreenLayout=YES/edgesForExtendedLayout=UIRectEdgeAll,全屏隱藏狀態欄(包括熱點欄)、導航欄和工具欄之後高度為SCREEN_HEIGHT。
    {
        contentRect = CGRectMake(0, 0, hostView.width, hostView.height);
    }


    // ...

}


- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];



    // ...


    if (_bFullScreen)
    {
        if (SYSTEM_VERSION >= 7.0)
        {
            self.extendedLayoutIncludesOpaqueBars = YES;
            self.edgesForExtendedLayout = UIRectEdgeAll;
        }
        else
        {
            self.wantsFullScreenLayout = YES;
            self.navigationController.navigationBar.translucent = YES; // iOS 6下保證導航欄透明
        }
    }
    else
    {
        [[UIApplication sharedApplication] setStatusBarStyle:_lastStatusBarStyle];
        if (SYSTEM_VERSION >= 7.0)
        {
            // 設置後:有個人熱點連接時,UIViewController.view自動下移20;無個人熱點連接時,UIViewController.view自動上移20
            self.extendedLayoutIncludesOpaqueBars= NO;
            self.edgesForExtendedLayout = UIRectEdgeNone;
        }
        else
        {
            self.wantsFullScreenLayout = NO;
            self.navigationController.navigationBar.translucent = _lastBarTranslucent;
        }

    }


    // ...
}

// 手動點擊內容區域做到全屏
- (void)setFullScreen:(BOOL)bFull

{

    _bFullScreen = bFull;

    // 全屏(非全屏)隱藏(顯示)系統狀態欄
    [[UIApplication sharedApplication] setStatusBarHidden:bFullScreen];
    // 全屏(非全屏)隱藏(顯示)頂部導航欄
    [self.navigationController setNavigationBarHidden:bFullScreen animated:YES];
    // 全屏(非全屏)隱藏(顯示)底部工具欄

    [self.navigationController setToolbarHidden:bFullScreen animated:YES];


    // ...

}


#pragma mark UIApplicationWillChangeStatusBarFrameNotification
// 如有必要,需監聽系統狀態欄變更通知:UIApplicationWillChangeStatusBarFrameNotification

- (void)handleUIApplicationWillChangeStatusBarFrameNotification:(NSNotification*)notification
{
    CGRect newStatusBarFrame = [(NSValue*)[notification.userInfo objectForKey:UIApplicationStatusBarFrameUserInfoKey] CGRectValue];

    // 根據系統狀態欄高判斷熱點欄的變動
    BOOL bPersonalHotspotConnected = (CGRectGetHeight(newStatusBarFrame)==(SYS_STATUSBAR_HEIGHT+HOTSPOT_STATUSBAR_HEIGHT)?YES:NO);

    CGPoint newCenter = CGPointZero;
    CGFloat OffsetY = bPersonalHotspotConnected?+HOTSPOT_STATUSBAR_HEIGHT:-HOTSPOT_STATUSBAR_HEIGHT;
    if (SYSTEM_VERSION >= 7.0) { // 即使設置了extendedLayoutIncludesOpaqueBars=NO/edgesForExtendedLayout=UIRectEdgeNone,對沒有自動調整的部分View做必要的手動調整
        newCenter = self.someSubView.center;
        newCenter.y += OffsetY;
        self.someSubView.center = newCenter;
    } else { // Custom Content對應的view整體調整
        newCenter = self.contentView.center;
        newCenter.y += OffsetY;
        self.contentView.center = newCenter; // contentView為Custom Content對應的view
    }
}

@end

四.iPhone/iOS個人熱點的interface

iPhone開啟個人熱點(橋接上網)時,會多出bridge接口。

iPhone5s/iOS8.2開啟個人熱點時,遍歷可發現多出3個活躍的bridge100接口(IFF_UP),sa_family分別是AF_LINK(18)、AF_INET6(30)、AF_INET(2)。

遍歷interface的代碼片段如下:

struct ifaddrs *interfaces = nil;

if(!getifaddrs(&interfaces))

{

    for(structifaddrs *interface = interfaces; interface; interface = interface->ifa_next) {

            if ((interface->ifa_flags&IFF_UP) ==IFF_UP) {

                log_notice("ifa_name : %s, ifa_addr->sa_family : %d", interface->ifa_name, interface->ifa_addr->sa_family);

            }

       }

}

if (interfaces) {

    freeifaddrs(interfaces);

    interfaces = NULL;

}

參考

《iOS7兼容之前版本》

http://www.cnblogs.com/zcw-ios/articles/3340197.html

《iOS7適配》

http://blog.csdn.net/toss156/article/details/11843873

《iOS7 UI適配》

http://www.tekuba.net/wap.asp?act=View&id=344

《iOS7遇到的一些問題及解決方法》

http://blog.csdn.net/cssmhyl/article/details/17582261

《iOS7用代碼解決視圖控制器的View整體上移問題》

http://blog.csdn.net/kmyhy/article/details/20444611

閱讀原文


關於作者:
最新iOS、iPhone資訊,萬名iOS開發者、swift開發、果粉聚集,參與技術討論,整理開發技巧,分享創業經驗!享受生活、熱愛編程!

微信號:iOSDevTip