SwiftUI框架詳細(xì)解析 (四) —— 使用SwiftUI進(jìn)行蘋果登錄(一)

版本記錄

版本號 時(shí)間
V1.0 2019.10.17 星期四

前言

今天翻閱蘋果的API文檔直晨,發(fā)現(xiàn)多了一個(gè)框架SwiftUI搀军,這里我們就一起來看一下這個(gè)框架。感興趣的看下面幾篇文章勇皇。
1. SwiftUI框架詳細(xì)解析 (一) —— 基本概覽(一)
2. SwiftUI框架詳細(xì)解析 (二) —— 基于SwiftUI的閃屏頁的創(chuàng)建(一)
3. SwiftUI框架詳細(xì)解析 (三) —— 基于SwiftUI的閃屏頁的創(chuàng)建(二)

開始

主要內(nèi)容:了解如何使用SwiftUI實(shí)施與Apple的登錄罩句,以為用戶提供更多的隱私和對iOS應(yīng)用程序的控制,本篇翻譯來自地址敛摘。

下面看下寫作環(huán)境

Swift 5, iOS 13, Xcode 11

使用Apple登錄(Sign In with Apple)iOS 13中的一項(xiàng)新功能门烂,可以更快地在您的應(yīng)用程序中注冊和認(rèn)證。

盡管Apple反復(fù)聲明“與Apple登錄”易于實(shí)現(xiàn)兄淫,但仍存在一些需要管理的地方屯远。 在本教程中,您不僅將學(xué)習(xí)如何正確使用Apple實(shí)施登錄捕虽,而且還將學(xué)習(xí)如何使用SwiftUI慨丐!

您需要Xcode 11,付費(fèi)的Apple Developer會(huì)員身份和iOS 13設(shè)備泄私,才能隨本教程一起學(xué)習(xí)房揭。

注意:您需要一臺(tái)運(yùn)行iOS 13的實(shí)際設(shè)備。模擬器并不總是能夠正常運(yùn)行晌端。

由于您將在設(shè)備上運(yùn)行并處理授權(quán)捅暴,因此請轉(zhuǎn)到“項(xiàng)目”導(dǎo)航器,然后單擊新的Signing & Capabilities標(biāo)簽咧纠,以設(shè)置團(tuán)隊(duì)標(biāo)識符并適當(dāng)更新包標(biāo)識符伶唯。 如果您現(xiàn)在構(gòu)建并運(yùn)行該應(yīng)用程序,則會(huì)看到正常的登錄屏幕:

注意:您可以忽略Xcode顯示的兩個(gè)警告惧盹。 您將在教程中對其進(jìn)行修復(fù)乳幸。


Add Capabilities

您的配置(PP)文件需要具有Sign In with Apple功能瞪讼,因此請立即添加。 在項(xiàng)目導(dǎo)航器中單擊項(xiàng)目粹断,選擇SignInWithApple目標(biāo)符欠,然后單擊Signing & Capabilities選項(xiàng)卡。 最后瓶埋,單擊+ Capability希柿,然后添加使用Apple登錄功能。

如果您的應(yīng)用程序具有關(guān)聯(lián)的網(wǎng)站养筒,則還應(yīng)該添加Associated Domains功能曾撤。 此步驟是完全可選的,對于本教程或使用Apple登錄功能來說不是必需的晕粪。 如果確實(shí)選擇使用關(guān)聯(lián)的域挤悉,請確保將“域” Domains值設(shè)置為字符串webcredentials :,后跟域名巫湘。 例如装悲,您可以使用webcredentials:www.mydomain.com。 在本教程的后面尚氛,您將了解需要對網(wǎng)站進(jìn)行的更改诀诊。


Add Sign In Button

Apple沒有為Sign In with Apple按鈕提供SwiftUI視圖,因此您需要自己包裝阅嘶。 創(chuàng)建一個(gè)名為SignInWithApple.swift的新文件属瓣,然后粘貼此代碼。

import SwiftUI
import AuthenticationServices

// 1
final class SignInWithApple: UIViewRepresentable {
  // 2
  func makeUIView(context: Context) -> ASAuthorizationAppleIDButton {
    // 3
    return ASAuthorizationAppleIDButton()
  }
  
  // 4
  func updateUIView(_ uiView: ASAuthorizationAppleIDButton, context: Context) {
  }
}

這是正在做的事情:

  • 1) 需要包裝UIView時(shí)讯柔,可以將UIViewRepresentable子類化奠涌。
  • 2) makeUIView應(yīng)該始終返回特定類型的UIView
  • 3) 由于您沒有執(zhí)行任何自定義操作磷杏,因此直接返回“使用Apple登錄”對象溜畅。
  • 4) 由于視圖的狀態(tài)永遠(yuǎn)不變,因此請保留一個(gè)空的實(shí)現(xiàn)极祸。

現(xiàn)在您可以將按鈕添加到SwiftUI慈格,打開ContentView.swift并將其添加到UserAndPassword視圖的正下方:

SignInWithApple()
  .frame(width: 280, height: 60)

Apple的樣式指南要求最小尺寸為280×60,因此請務(wù)必遵循遥金。 構(gòu)建并運(yùn)行您的應(yīng)用程序浴捆,您應(yīng)該會(huì)看到按鈕!


Handle Button Taps

現(xiàn)在稿械,點(diǎn)擊按鈕不會(huì)執(zhí)行任何操作选泻。 在設(shè)置按鈕frame的位置下方,添加一個(gè)手勢識別:

.onTapGesture(perform: showAppleLogin)

然后在body屬性之后實(shí)現(xiàn)showAppleLogin()

private func showAppleLogin() {
  // 1
  let request = ASAuthorizationAppleIDProvider().createRequest()

  // 2
  request.requestedScopes = [.fullName, .email]

  // 3
  let controller = ASAuthorizationController(authorizationRequests: [request])    
}

這是您設(shè)置的內(nèi)容:

  • 1) 所有登錄請求都需要一個(gè)ASAuthorizationAppleIDRequest
  • 2) 指定您需要知道的最終用戶數(shù)據(jù)的類型页眯。
  • 3) 生成將顯示登錄對話框的控制器梯捕。

您應(yīng)該僅請求所需的用戶數(shù)據(jù)。 Apple為您生成一個(gè)用戶ID窝撵。因此傀顾,如果獲取電子郵件的唯一目的是擁有一個(gè)唯一的標(biāo)識符,那么您就不需要它了碌奉,所以請不要請求短曾。

1. ASAuthorizationControllerDelegate

當(dāng)用戶嘗試進(jìn)行身份驗(yàn)證時(shí),Apple將調(diào)用兩個(gè)委托方法之一赐劣,因此請立即實(shí)施嫉拐。打開SignInWithAppleDelegates.swift。您將在此處實(shí)現(xiàn)代碼魁兼,該代碼將在用戶點(diǎn)擊按鈕后運(yùn)行婉徘。雖然您可以在自己的視圖中實(shí)現(xiàn)代碼,但將代碼放置在其他位置以提高可重用性會(huì)更簡潔璃赡。

您現(xiàn)在只需將authorizationController(controller:didCompleteWithError :)保留為空判哥,但在生產(chǎn)應(yīng)用中献雅,應(yīng)處理這些錯(cuò)誤碉考。

授權(quán)成功后,將調(diào)用authorizationController(controller:didCompleteWithAuthorization :)挺身。您可以在下載的示例代碼中看到兩種情況侯谁。通過檢查credential屬性,可以確定用戶是通過Apple ID還是通過存儲(chǔ)的iCloud密碼進(jìn)行了身份驗(yàn)證章钾。

傳遞給委托方法的ASAuthorization對象包括您要求的任何屬性墙贱,例如電子郵件或名稱。該值的存在是您如何確定這是新注冊還是現(xiàn)有登錄名的方式贱傀。

注意:Apple只會(huì)在首次身份驗(yàn)證時(shí)為您提供所需的詳細(xì)信息惨撇。

記住前面的注釋至關(guān)重要! Apple假設(shè)您將存儲(chǔ)所需的詳細(xì)信息府寒,因此不再需要它們魁衙。這是您需要處理的“與Apple登錄”的地方之一。

考慮用戶首次登錄的情況株搔,因此您需要執(zhí)行注冊。 Apple向您提供用戶的電子郵件和全名。然后碰煌,您嘗試調(diào)用您的服務(wù)器注冊代碼堕扶。除非您的服務(wù)器不在線或設(shè)備的網(wǎng)絡(luò)連接斷開等役拴。

用戶下次登錄時(shí)姜性,Apple不會(huì)提供詳細(xì)信息儡炼,因?yàn)樗M呀?jīng)擁有這些詳細(xì)信息妹田。這將導(dǎo)致existing user流運(yùn)行沮趣,從而導(dǎo)致失敗。

2. Handling Registration

authorizationController(controller:didCompleteWithAuthorization :)的第一個(gè)case語句中露懒,添加以下內(nèi)容:

// 1
if let _ = appleIdCredential.email, let _ = appleIdCredential.fullName {
  // 2
  registerNewAccount(credential: appleIdCredential)
} else {
  // 3
  signInWithExistingAccount(credential: appleIdCredential)
}

在此代碼中:

  • 1) 如果您收到詳細(xì)信息纺涤,則表明它是新注冊拧咳。
  • 2) 收到詳細(xì)信息后汪厨,請調(diào)用您的注冊方法狭吼。
  • 3) 如果您沒有收到詳細(xì)信息,請調(diào)用您現(xiàn)有的帳戶方法殖妇。

將以下注冊方法粘貼到擴(kuò)展名的頂部:

private func registerNewAccount(credential: ASAuthorizationAppleIDCredential) {
  // 1
  let userData = UserData(email: credential.email!,
                          name: credential.fullName!,
                          identifier: credential.user)

  // 2
  let keychain = UserDataKeychain()
  do {
    try keychain.store(userData)
  } catch {
    self.signInSucceeded(false)
  }

  // 3
  do {
    let success = try WebApi.Register(
      user: userData,
      identityToken: credential.identityToken,
      authorizationCode: credential.authorizationCode
    )
    self.signInSucceeded(success)
  } catch {
    self.signInSucceeded(false)
  }
}

這里做了一些事情:

  • 1) 將所需的詳細(xì)信息和Apple提供的user保存在結(jié)構(gòu)體中。
  • 2) 將詳細(xì)信息存儲(chǔ)到iCloud鑰匙串中以備后用葱椭。
  • 3) 調(diào)用您的服務(wù),并向調(diào)用者表明注冊是否成功粪小。

請注意credential.user的用法。此屬性包含Apple分配給最終用戶的唯一標(biāo)識符。當(dāng)您將此用戶存儲(chǔ)在服務(wù)器上時(shí)逞壁,請使用此值(而不是電子郵件或登錄名)流济。提供的值將在用戶擁有的所有設(shè)備上完全匹配。此外腌闯,Apple將為與您的Team ID相關(guān)聯(lián)的所有應(yīng)用程序?yàn)橛脩籼峁┫嗤闹瞪痢S脩暨\(yùn)行的任何應(yīng)用均會(huì)收到相同的ID,這意味著您已經(jīng)在服務(wù)器上擁有了他們的所有信息姿骏,無需要求用戶提供它糖声!

您服務(wù)器的數(shù)據(jù)庫可能已經(jīng)為用戶存儲(chǔ)了其他標(biāo)識符。只需在您的user類型表中添加一個(gè)新列分瘦,其中包含Apple提供的標(biāo)識符蘸泻。然后,您的服務(wù)器端代碼將首先檢查該列是否匹配嘲玫。如果未找到悦施,請還原為現(xiàn)有的登錄或注冊流程,例如使用電子郵件地址或登錄名去团。

根據(jù)服務(wù)器處理安全性的方式抡诞,您可能會(huì)或可能不需要發(fā)送credential.identityTokencredential.authorizationCode拜马。 OAuth流使用這兩部分?jǐn)?shù)據(jù)。 OAuth設(shè)置超出了本教程的范圍沐绒。

注意:Apple提供了使用OAuth詳細(xì)信息生成其公鑰所需的數(shù)據(jù)俩莽。本質(zhì)上,他們?yōu)槟峁┝?code>JSON Web Key (JWK)乔遮。

為了確保在鑰匙串中正確存儲(chǔ)扮超,請?jiān)?code>CredentialStorage中編輯UserDataKeychain.swift并更新account以獲取應(yīng)用程序的包標(biāo)識符,然后附加任何其他文本值蹋肮。我喜歡在包標(biāo)識符后附加.Details出刷。重要的是,account屬性和包標(biāo)識符不完全匹配坯辩,因此存儲(chǔ)的值僅用于您打算使用的目的馁龟。

3. Handling Existing Accounts

如前所述,現(xiàn)有用戶登錄到您的應(yīng)用程序時(shí)漆魔,Apple不會(huì)提供電子郵件和全名坷檩。在SignInWithAppleDelegates.swift中的注冊方法下面添加此方法以處理這種情況:

private func signInWithExistingAccount(credential: ASAuthorizationAppleIDCredential) {
  // You *should* have a fully registered account here.  If you get back an error
  // from your server that the account doesn't exist, you can look in the keychain 
  // for the credentials and rerun setup

  // if (WebAPI.login(credential.user, 
  //                  credential.identityToken,
  //                  credential.authorizationCode)) {
  //   ...
  // }

  self.signInSucceeded(true)
}

您在此方法中放置的代碼將非常針對應(yīng)用程序。 如果您從服務(wù)器收到失敗消息改抡,告知您該用戶尚未注冊矢炼,則應(yīng)使用retrieve()查詢鑰匙串。 使用返回的UserData結(jié)構(gòu)的詳細(xì)信息阿纤,然后重新嘗試注冊最終用戶句灌。

4. Username and Password

與Apple一起使用登錄時(shí),另一種可能性是最終用戶將選擇已存儲(chǔ)在該站點(diǎn)的iCloud鑰匙串中的憑據(jù)credentials欠拾。 在authorizationController(controller:didCompleteWithAuthorization :)的第二種case語句中胰锌,添加以下行:

signInWithUserAndPassword(credential: passwordCredential)

然后在signInWithExistingAccount(credential :)下面,實(shí)現(xiàn)適當(dāng)?shù)姆椒ǎ?/p>

private func signInWithUserAndPassword(credential: ASPasswordCredential) {
  // if (WebAPI.login(credential.user, credential.password)) {
  //   ...
  // }
  self.signInSucceeded(true)
}

同樣藐窄,您的實(shí)現(xiàn)將針對特定應(yīng)用资昧。 但是,您需要調(diào)用服務(wù)器登錄名并傳遞用戶名和密碼枷邪。 如果服務(wù)器無法識別用戶榛搔,則您將需要運(yùn)行完整的注冊流程诺凡,因?yàn)槟痪邆滂€匙串中提供的有關(guān)其電子郵件和姓名的任何詳細(xì)信息东揣。


Finish Handling Button Press

返回ContentView.swift,您需要一個(gè)屬性來存儲(chǔ)剛創(chuàng)建的代理腹泌。 在類的頂部嘶卧,添加以下代碼行:

@State var appleSignInDelegates: SignInWithAppleDelegates! = nil

@State是告訴SwiftUI的結(jié)構(gòu)將擁有其擁有并更新的可變內(nèi)容。 所有@State屬性必須具有一個(gè)實(shí)際值凉袱,這就是為什么出現(xiàn)nil奇怪的賦值的原因芥吟。

現(xiàn)在侦铜,在同一文件中,用以下命令替換controller創(chuàng)建钟鸵,以完成showAppleLogin()

// 1
appleSignInDelegates = SignInWithAppleDelegates() { success in
  if success {
    // update UI 
  } else {
    // show the user an error
  }
}

// 2
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = appleSignInDelegates

// 3
controller.performRequests()

這是正在做的事情:

  • 1) 生成代理并將其分配給類的屬性钉稍。
  • 2) 像以前一樣生成ASAuthorizationController,但是這次棺耍,告訴它使用您的自定義委托類贡未。
  • 3) 通過調(diào)用performRequests(),您要求iOS顯示Sign In with Apple模式視圖蒙袍。

代理的回調(diào)是根據(jù)最終用戶是否成功通過您的應(yīng)用進(jìn)行身份驗(yàn)證來處理任何必要的展示更改的地方俊卤。


Automate Sign In

您已經(jīng)實(shí)現(xiàn)了使用Apple登錄的功能,但是用戶必須明確點(diǎn)擊該按鈕害幅。 如果已將他們帶到登錄頁面消恍,則應(yīng)查看他們是否已配置Sign In with Apple。 返回ContentView.swift以现,將此行添加到.onAppear塊中:

 self.performExistingAccountSetupFlows()

注意:SwiftUI.onAppear {}UIKitviewDidAppear(_ :)基本相同狠怨。

當(dāng)視圖出現(xiàn)時(shí),您希望iOS同時(shí)檢查Apple IDiCloud鑰匙串以查找與此應(yīng)用程序相關(guān)的憑據(jù)邑遏。 如果存在取董,則將自動(dòng)顯示Sign In with Apple對話框,因此用戶不必手動(dòng)按下按鈕无宿。 由于同時(shí)按下按鈕和自動(dòng)調(diào)用都共享代碼茵汰,因此將showAppleLogin方法重構(gòu)為兩種方法:

private func showAppleLogin() {
  let request = ASAuthorizationAppleIDProvider().createRequest()
  request.requestedScopes = [.fullName, .email]
  
  performSignIn(using: [request])
}

private func performSignIn(using requests: [ASAuthorizationRequest]) {
  appleSignInDelegates = SignInWithAppleDelegates() { success in
    if success {
      // update UI
    } else {
      // show the user an error
    }
  }

  let controller = ASAuthorizationController(authorizationRequests: requests)
  controller.delegate = appleSignInDelegates

  controller.performRequests()
}

除了將代理的創(chuàng)建和顯示移至其自己的方法之外,沒有任何代碼更改孽鸡。

現(xiàn)在蹂午,實(shí)現(xiàn)performExistingAccountSetupFlows()

private func performExistingAccountSetupFlows() {
  // 1
  #if !targetEnvironment(simulator)

  // 2
  let requests = [
    ASAuthorizationAppleIDProvider().createRequest(),
    ASAuthorizationPasswordProvider().createRequest()
  ]

  // 2
  performSignIn(using: requests)
  #endif
}

這里只有幾個(gè)步驟:

  • 1) 如果您使用的是模擬器,則什么也不做彬碱。如果您進(jìn)行這些調(diào)用豆胸,模擬器將打印出錯(cuò)誤。
  • 2) 要求Apple提出對Apple IDiCloud鑰匙串檢查的請求巷疼。
  • 3) 調(diào)用您現(xiàn)有的安裝代碼晚胡。

請注意,在第2步中嚼沿,您沒有指定要檢索哪些最終用戶詳細(xì)信息估盘。回想一下本教程的前面部分骡尽,您在該教程中了解到遣妥,僅一次提供了詳細(xì)信息。由于此流程用于檢查現(xiàn)有帳戶攀细,因此無需指定requestedScopes屬性箫踩。實(shí)際上爱态,如果您在此處設(shè)置了它,它將被忽略境钟!


Web Credentials

如果您有專門針對您的應(yīng)用程序的網(wǎng)站锦担,則可以走做的更多,也可以處理Web憑據(jù)慨削。如果您查看UserAndPassword.swift吆豹,則會(huì)看到對SharedWebCredential(domain :)的調(diào)用,該調(diào)用當(dāng)前向構(gòu)造函數(shù)發(fā)送一個(gè)空字符串理盆。將其替換為您的網(wǎng)站域痘煤。

現(xiàn)在,登錄到您的網(wǎng)站猿规,并在網(wǎng)站的根目錄下創(chuàng)建一個(gè)名為.well-known的目錄衷快。在其中創(chuàng)建一個(gè)名為apple-app-site-association的新文件,并粘貼以下JSON

{
    "webcredentials": {
        "apps": [ "ABCDEFGHIJ.com.raywenderlich.SignInWithApple" ]
    }
}

注意:確保文件名沒有擴(kuò)展名姨俩。

您需要將ABCDEFGHIJ替換為團(tuán)隊(duì)的10個(gè)字符的Team ID蘸拔。 您可以在Membership選項(xiàng)卡下的https://developer.apple.com/account中找到您的Team ID。 您還需要使bundle identifier與您用于該應(yīng)用程序的標(biāo)識符匹配环葵。

通過執(zhí)行這些步驟调窍,您已將Safari存儲(chǔ)的登錄詳細(xì)信息與應(yīng)用程序的登錄詳細(xì)信息相關(guān)聯(lián)。 它們現(xiàn)在可用于Sign in with Apple张遭。

當(dāng)用戶手動(dòng)輸入用戶名和密碼時(shí)邓萨,將存儲(chǔ)憑據(jù),以便以后使用菊卷。


Runtime Checks

在應(yīng)用程序生命周期內(nèi)的任何時(shí)候缔恳,用戶都可以進(jìn)入設(shè)備設(shè)置并為您的應(yīng)用程序禁用Sign In with Apple。 您將根據(jù)要執(zhí)行的操作檢查它們是否仍在登錄洁闰。Apple建議您運(yùn)行以下代碼:

let provider = ASAuthorizationAppleIDProvider()
provider.getCredentialState(forUserID: "currentUserIdentifier") { state, error in
  switch state {
  case .authorized:
    // Credentials are valid.
    break
  case .revoked:
    // Credential revoked, log them out
    break
  case .notFound:
    // Credentials not found, show login UI
    break
  }
}

蘋果公司表示歉甚,getCredentialState(forUserId :)調(diào)用非常快扑眉。 因此纸泄,您應(yīng)該在應(yīng)用啟動(dòng)期間以及需要確保用戶仍然通過身份驗(yàn)證的任何時(shí)間運(yùn)行它。 我建議您除非必須腰素,否則不要在應(yīng)用程序啟動(dòng)時(shí)運(yùn)行聘裁。 您的應(yīng)用真的需要登錄或注冊用戶才能使用嗎? 在他們嘗試執(zhí)行實(shí)際上需要登錄的操作之前耸弄,無需他們登錄咧虎。實(shí)際上,甚至Human Interface Guidelines也建議這樣做计呈!

請記住砰诵,如果要求他們做的第一件事是注冊,那么許多用戶將卸載剛剛下載的應(yīng)用程序捌显。

相反茁彭,請監(jiān)聽Apple提供的通知以了解用戶何時(shí)登出。 只需偵聽ASAuthorizationAppleIDProvider.credentialRevokedNotification通知并采取適當(dāng)?shù)拇胧?/p>


The UIWindow

至此扶歪,您已經(jīng)完全實(shí)現(xiàn)了Sign In with Apple理肺。 恭喜你!

如果您觀看了有關(guān)使用Apple登錄的WWDC演示文稿善镰,或者已閱讀其他教程妹萨,則可能會(huì)發(fā)現(xiàn)這里缺少一塊。 您從未實(shí)現(xiàn)過ASAuthorizationControllerPresentationContextProviding代理方法來告訴iOS使用哪個(gè)UIWindow炫欺。 從技術(shù)上講乎完,如果您使用默認(rèn)的UIWindow并不是必需的,那么最好知道如何處理品洛。

如果您不使用SwiftUI树姨,那么從SceneDelegate中獲取window屬性并返回值非常簡單。 在SwiftUI中桥状,它變得更加困難帽揪。


The Environment

SwiftUI的新概念是Environment。 在該區(qū)域中辅斟,您可以存儲(chǔ)需要用于許多SwiftUI視圖的數(shù)據(jù)转晰。 在某種程度上,您可以將其視為依賴注入士飒。

1. Environment Setup

看一下EnvironmentWindowKey.swift挽霉,您將看到在SwiftUI環(huán)境中存儲(chǔ)值所需的代碼。 它是樣板代碼变汪,其中您定義了要傳遞給@Environment屬性包裝器的鍵以及要存儲(chǔ)的值侠坎。 請注意,由于存儲(chǔ)了類的類型裙盾,因此如何將其顯式標(biāo)記為weak引用以防止循環(huán)引用实胸。

注意:環(huán)境代碼是由WWDC實(shí)驗(yàn)室中的Apple工程師提供的

2. ContentView Changes

跳回到ContentView.swift并在ContentView的頂部添加另一個(gè)屬性:

@Environment(\.window) var window: UIWindow?

iOS會(huì)自動(dòng)使用存儲(chǔ)在環(huán)境中的值填充window變量。

performSignIn(using :)中番官,修改構(gòu)造函數(shù)調(diào)用以傳遞window屬性:

appleSignInDelegates = SignInWithAppleDelegates(window: window) { success in

您還需要告訴ASAuthorizationController將您的類用于presentationContextProvider代理庐完,因此請?jiān)诜峙?code>controller.delegate后立即添加以下代碼。

controller.presentationContextProvider = appleSignInDelegates

3. Update the Delegate

打開SignInWithAppleDelegates.swift處理新屬性徘熔,并對類進(jìn)行構(gòu)造函數(shù)更改门躯。 使用以下所有類的注冊和委托方法而不是擴(kuò)展替換類定義:

class SignInWithAppleDelegates: NSObject {
  private let signInSucceeded: (Bool) -> Void
  // 1
  private weak var window: UIWindow!

  // 2
  init(window: UIWindow?, onSignedIn: @escaping (Bool) -> Void) {
    // 3
    self.window = window
    self.signInSucceeded = onSignedIn
  }
}

只是一些更改:

  • 1) 存儲(chǔ)新的對windowweak引用。
  • 2) 將UIWindow參數(shù)作為第一個(gè)參數(shù)添加到初始化程序酷师。
  • 3) 將傳入的值存儲(chǔ)到屬性讶凉。

最后染乌,實(shí)現(xiàn)新的代理類型:

extension SignInWithAppleDelegates: 
    ASAuthorizationControllerPresentationContextProviding {
  func presentationAnchor(for controller: ASAuthorizationController) 
      -> ASPresentationAnchor {
    return self.window
  }
}

代理只有一種方法可以實(shí)現(xiàn),該方法可以返回window懂讯,該窗口顯示Sign In with Apple模式對話框荷憋。

4. Update the Scene

UIWindow放入環(huán)境是最后要做的事。 打開SceneDelegate.swift并替換以下行:

window.rootViewController = UIHostingController(rootView: ContentView())

用下面內(nèi)容

// 1
let rootView = ContentView().environment(\.window, window)

// 2
window.rootViewController = UIHostingController(rootView: rootView)

只需兩個(gè)小步驟即可完成所有操作:

  • 1) 您創(chuàng)建ContentView并附加window變量的值褐望。
  • 2) 您將該rootView變量傳遞給UIHostingController而不是舊的初始化程序勒庄。

environment方法會(huì)返回some View,這基本上意味著它將使用您的ContentView瘫里,將您傳遞的值推入該視圖的環(huán)境中实蔽,然后將ContentView返回給您。 現(xiàn)在谨读,從ContentView呈現(xiàn)的任何SwiftUI View也會(huì)在其環(huán)境中保留該值局装。

如果您在其他任何地方創(chuàng)建新的根視圖,則該根將不包含環(huán)境值漆腌,除非您也明確地將它們返回贼邓。


Logins Do not Scroll

使用Apple登錄時(shí)要記住的一個(gè)缺點(diǎn)是,iOS顯示的window不會(huì)滾動(dòng)闷尿! 對于大多數(shù)用戶而言塑径,這無關(guān)緊要,但是請務(wù)必注意填具。 例如统舀,作為我的應(yīng)用程序使用的網(wǎng)站的所有者,我擁有許多登錄名劳景。 我不僅可以自己登錄應(yīng)用程序誉简,而且還可以登錄SQL數(shù)據(jù)庫,PHP管理站點(diǎn)等盟广。

如果您登錄的次數(shù)過多闷串,則最終用戶可能看不到他們的實(shí)際需求。 嘗試確保將應(yīng)用程序鏈接到網(wǎng)站時(shí)筋量,該網(wǎng)站僅具有對應(yīng)用程序重要的登錄信息烹吵。 不要將所有應(yīng)用捆綁在一個(gè)域中。

后記

本篇主要講述了使用SwiftUI進(jìn)行蘋果登錄桨武,感興趣的給個(gè)贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肋拔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呀酸,更是在濱河造成了極大的恐慌凉蜂,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異窿吩,居然都是意外死亡茎杂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門爆存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛉顽,“玉大人蝗砾,你說我怎么就攤上這事先较。” “怎么了悼粮?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵闲勺,是天一觀的道長。 經(jīng)常有香客問我扣猫,道長菜循,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任申尤,我火速辦了婚禮癌幕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昧穿。我一直安慰自己勺远,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布时鸵。 她就那樣靜靜地躺著胶逢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饰潜。 梳的紋絲不亂的頭發(fā)上初坠,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音彭雾,去河邊找鬼碟刺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛薯酝,可吹牛的內(nèi)容都是我干的半沽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蜜托,長吁一口氣:“原來是場噩夢啊……” “哼抄囚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橄务,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤幔托,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體重挑,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗓化,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谬哀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刺覆。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖史煎,靈堂內(nèi)的尸體忽然破棺而出谦屑,到底是詐尸還是另有隱情,我是刑警寧澤篇梭,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布氢橙,位于F島的核電站,受9級特大地震影響恬偷,放射性物質(zhì)發(fā)生泄漏悍手。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一袍患、第九天 我趴在偏房一處隱蔽的房頂上張望坦康。 院中可真熱鬧,春花似錦诡延、人聲如沸滞欠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仑撞。三九已至,卻和暖如春妖滔,著一層夾襖步出監(jiān)牢的瞬間隧哮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工座舍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沮翔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓曲秉,卻偏偏與公主長得像采蚀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子承二,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

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