「 iOS知識小集 」2018 · 第 41 期

知識小集發表於2018-12-17

原文連結

上週公眾號釋出的以下文章:

本期知識小集的主要內容包括:

  • 一入IAP深似海第二彈
  • Xcode 10 / iOS 12 獲取 WiFi 資訊
  • Swift 4.x 中使用 +load 和 +initialize
  • SecRandomCopyBytes 生成偽隨機數

一入IAP深似海第二彈

作者: 高老師很忙

之前和大家分享過一次關於IAP的坑,最近又發現了一個新坑?:通常我們是根據-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions方法回撥來確認使用者支付成功還是失敗,從而進入不同的業務處理;然而我最近發現蘋果可能會返回錯誤的回撥,使用者實際已經支付成功,但是會先收到一次取消支付的回撥,然後馬上又收到一個支付成功的回撥。

針對這種情況,就需要我們在業務上進一步處理,同時還要兼顧之前分享的關於丟單處理的邏輯,防止丟單會涉及一些訂單資訊的本地儲存,之前可能會在收到取消支付回撥時刪除對應的本地訂單資訊,這種情況就需要重新補充訂單資訊。

Xcode 10 / iOS 12 獲取 WiFi 資訊

作者: KANGZUBIN

在一些特定業務場景下,我們需要獲取 iOS 裝置所連線的 WiFi 的資訊,比如 WiFi 的 SSID(即 WiFi 的名稱),WiFi 的 BSSID(即 WiFi 的路由器的 Mac 地址)等,相應的程式碼也很簡單,大致如下圖所示:

「 iOS知識小集 」2018 · 第 41 期

在 Xcode 10(iOS 12)之前,上述程式碼可以正常執行取到結果,但當升級到 Xcode 10 後編譯工程在 iOS 12 上執行時,同樣的程式碼卻無法取得 WiFi 的資訊。通過斷點除錯發現 CNCopyCurrentNetworkInfo(...) 函式總是返回 nil,查閱官方 API 文件,發現該函式的描述多了一條重要提示,如下圖紅框內容:

「 iOS知識小集 」2018 · 第 41 期

大致意思是說:在 iOS 12 及以上系統呼叫該方法時,需要先在 Xcode 工程中授權獲取 WiFi 資訊的能力,開啟路徑為:Xcode -> [Project Name] -> Targets -> [Target Name] -> Capabilities -> Access WiFi Information -> ON,如下圖:

「 iOS知識小集 」2018 · 第 41 期

設定完畢後,我們可以發現在工程的 .entitlements 檔案會多了一對鍵值:

Access WiFi Information => YES

至此,我們就可以正常在 iOS 12+ 中獲取 WiFi 的資訊了。

Swift 4.x 中使用 +load 和 +initialize

+load 和 +initialize 方法是我們寫 Objective-C 程式碼時常用的兩個方法,不過貌似在 Swift 4.x 後,這兩個方法在 Swift 類中不那麼好使,會報如下編譯錯誤:

Method 'load()' defines Objective-C class method 'load', which is not permitted by Swift

Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift
複製程式碼

所以,如果想在 Swift 類中使用這兩個方法,則需要求助於 Objective-C,使用變通的方法,如下程式碼所示:

// swift
class Monitor: NSObject {
	@objc class func swiftLoad() {
		// do something
		print("swift load")
	}

	@objc class func swiftInitialize() {
		// do something
		print("swift initialize")
	}
}

// Objective-C
@implementation Monitor (Private)

+ (void)load {
	[self swiftLoad];
}

+ (void)initialize {
	[self swiftInitialize];
}

@end
複製程式碼

當然,由於這兩個方法是 NSObject 類中宣告的,所以我們的 Swift 類必須繼承自 NSObject 或其子類。另外,我們也可以不用上面這麼麻煩地去定義 swiftLoad/swiftInitialize 方法,而是所有操作直接在 Objective-C 程式碼中完成。

SecRandomCopyBytes 生成偽隨機數

在iOS中,生成偽隨機數可以使用這麼幾個函式:rand()random()arc4random()。另外我們知道隨機數是密碼技術的核心部分,所以 Apple 也為我們提供了相應的生成隨機數的方法,即 SecRandomCopyBytes,這個方法位於 Security.framework 中,所以使用時需要先匯入這個庫,使用的方法如下:

+ (NSString *)generateRandom {

    static int size = 8;
    uint8_t randomBytes[size];
    int result = SecRandomCopyBytes(kSecRandomDefault, size, randomBytes);
    if (result == errSecSuccess) {
        NSMutableString *randomString = [[NSMutableString alloc] initWithCapacity:size * 2];
        for (int i = 0; i < size; i++) {
            [randomString appendFormat:@"%02x", randomBytes[i]];
        }

        return randomString;
    } else {
        return nil;
    }
}
複製程式碼

這裡我們生成一個 8 位元組長的uint8_t陣列,然後將其轉換成 hex 字串得到一個長度16的隨機字條串。另外這個函式也可以作為生成 UUID 的輔助操作,如下程式碼所示:

+ (NSString*)generateCryptoSecureUUID
{
    unsigned char bytes[16];
    int result = SecRandomCopyBytes(kSecRandomDefault, 16, bytes);
    if (result != noErr) {
        return nil;
    }
    return [[NSUUID alloc] initWithUUIDBytes:bytes].UUIDString;
}
複製程式碼

關注我們

歡迎關注我們的公眾號:iOS-Tips,也歡迎加入我們的群組討論問題。可以公眾號留言 iosflutter 等關鍵詞獲取入群方式。

「 iOS知識小集 」2018 · 第 41 期

相關文章