From 8a05ab7a8b134fa6fbb4ec0bfc67410c54ec56f2 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Tue, 17 Sep 2024 10:07:33 -0600 Subject: [PATCH 01/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow --- iOSNativeSwiftTemplate/Podfile | 4 +- .../project.pbxproj | 114 ++++++++++-- .../iOSNativeSwiftTemplate/AppDelegate.swift | 3 + .../iOSNativeSwiftTemplate/Info.plist | 36 ++-- .../LoginTypeSelectionViewController.swift | 80 +++++++++ .../QrCodeScanController.swift | 163 ++++++++++++++++++ .../iOSNativeSwiftTemplate/bootconfig.plist | 4 +- 7 files changed, 367 insertions(+), 37 deletions(-) create mode 100644 iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift create mode 100644 iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift diff --git a/iOSNativeSwiftTemplate/Podfile b/iOSNativeSwiftTemplate/Podfile index 5e7b5019..8b1e4d46 100644 --- a/iOSNativeSwiftTemplate/Podfile +++ b/iOSNativeSwiftTemplate/Podfile @@ -1,4 +1,4 @@ -require_relative './mobile_sdk/SalesforceMobileSDK-iOS/mobilesdk_pods' +require_relative '../../SalesforceMobileSDK-iOS/mobilesdk_pods' platform :ios, '16.0' @@ -14,4 +14,4 @@ post_install do |installer| signposts_post_install(installer) mobile_sdk_post_install(installer) -end \ No newline at end of file +end diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj index 653a9efb..2e95b00e 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj @@ -18,13 +18,17 @@ 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */; }; 4FD6C4A01B755242002F9F90 /* InitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */; }; 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */; }; - B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */; }; + 8A7D16C2D3B653B9C7BC8413 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E4923BCE151D652A2E314ED /* Pods_iOSNativeSwiftTemplate.framework */; }; B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73B520C234FA65F001B069B /* SceneDelegate.swift */; }; B77BD8A321125B510036B284 /* bootconfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = B77BD8A221125B510036B284 /* bootconfig.plist */; }; - CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEA8CA031F071B2300448B51 /* Images.xcassets */; }; + D35055542C879DD500DCDC31 /* LoginTypeSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35055532C879DD500DCDC31 /* LoginTypeSelectionViewController.swift */; }; + D3848AE42C82351300A78C0A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3848AE22C82351300A78C0A /* Images.xcassets */; }; + D3848AE52C82351400A78C0A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D3848AE32C82351300A78C0A /* LaunchScreen.storyboard */; }; + D3848AE92C82392600A78C0A /* QrCodeScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3848AE82C82392600A78C0A /* QrCodeScanController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 42BEE51B49F5BAD7CCCD23AB /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.debug.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.debug.xcconfig"; sourceTree = ""; }; 4F13E936237DD5D9005BCAE9 /* ContactDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactDetailsView.swift; sourceTree = ""; }; 4F13E937237DD5D9005BCAE9 /* ContactsForAccountModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountModel.swift; sourceTree = ""; }; 4F13E938237DD5D9005BCAE9 /* ContactsForAccountListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountListView.swift; sourceTree = ""; }; @@ -39,10 +43,14 @@ 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InitialViewController.swift; sourceTree = ""; }; 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iOSNativeSwiftTemplate.entitlements; sourceTree = ""; }; 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; + 83C576D5B3530B7210E42288 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.release.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.release.xcconfig"; sourceTree = ""; }; + 9E4923BCE151D652A2E314ED /* Pods_iOSNativeSwiftTemplate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOSNativeSwiftTemplate.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B73B520C234FA65F001B069B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; B77BD8A221125B510036B284 /* bootconfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = bootconfig.plist; sourceTree = ""; }; - CEA8CA031F071B2300448B51 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = SOURCE_ROOT; }; + D35055532C879DD500DCDC31 /* LoginTypeSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginTypeSelectionViewController.swift; sourceTree = ""; }; + D3848AE22C82351300A78C0A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "../../../SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = ""; }; + D3848AE32C82351300A78C0A /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../../../SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; + D3848AE82C82392600A78C0A /* QrCodeScanController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeScanController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -50,19 +58,37 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 8A7D16C2D3B653B9C7BC8413 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 231DD8297D85560CF8533961 /* Pods */ = { + isa = PBXGroup; + children = ( + 42BEE51B49F5BAD7CCCD23AB /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */, + 83C576D5B3530B7210E42288 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 38A3D00284A22BBDCDF04290 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9E4923BCE151D652A2E314ED /* Pods_iOSNativeSwiftTemplate.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 4F13E944237DD626005BCAE9 /* SwiftUI */ = { isa = PBXGroup; children = ( - B73B520C234FA65F001B069B /* SceneDelegate.swift */, 4F13E939237DD5D9005BCAE9 /* AccountsListView.swift */, - 4F13E938237DD5D9005BCAE9 /* ContactsForAccountListView.swift */, 4F13E936237DD5D9005BCAE9 /* ContactDetailsView.swift */, + 4F13E938237DD5D9005BCAE9 /* ContactsForAccountListView.swift */, + B73B520C234FA65F001B069B /* SceneDelegate.swift */, ); name = SwiftUI; sourceTree = ""; @@ -71,8 +97,8 @@ isa = PBXGroup; children = ( 4F13E946237DD72E005BCAE9 /* AccountsListModel.swift */, - 4F13E937237DD5D9005BCAE9 /* ContactsForAccountModel.swift */, 4F13E93A237DD5D9005BCAE9 /* ContactDetailModel.swift */, + 4F13E937237DD5D9005BCAE9 /* ContactsForAccountModel.swift */, ); name = Models; sourceTree = ""; @@ -80,7 +106,9 @@ 4FD6C46B1B754AF1002F9F90 = { isa = PBXGroup; children = ( + 38A3D00284A22BBDCDF04290 /* Frameworks */, 4FD6C4761B754AF1002F9F90 /* iOSNativeSwiftTemplate */, + 231DD8297D85560CF8533961 /* Pods */, 4FD6C4751B754AF1002F9F90 /* Products */, ); sourceTree = ""; @@ -96,9 +124,9 @@ 4FD6C4761B754AF1002F9F90 /* iOSNativeSwiftTemplate */ = { isa = PBXGroup; children = ( - 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */, 4FD6C4A11B755265002F9F90 /* Classes */, 4FD6C4771B754AF1002F9F90 /* Supporting Files */, + 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */, ); path = iOSNativeSwiftTemplate; sourceTree = ""; @@ -106,13 +134,13 @@ 4FD6C4771B754AF1002F9F90 /* Supporting Files */ = { isa = PBXGroup; children = ( + B77BD8A221125B510036B284 /* bootconfig.plist */, + D3848AE22C82351300A78C0A /* Images.xcassets */, + 4FD6C4781B754AF1002F9F90 /* Info.plist */, + D3848AE32C82351300A78C0A /* LaunchScreen.storyboard */, 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */, 4F13E941237DD5EE005BCAE9 /* userstore.json */, 4F13E940237DD5EE005BCAE9 /* usersyncs.json */, - B77BD8A221125B510036B284 /* bootconfig.plist */, - B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */, - CEA8CA031F071B2300448B51 /* Images.xcassets */, - 4FD6C4781B754AF1002F9F90 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; @@ -120,10 +148,12 @@ 4FD6C4A11B755265002F9F90 /* Classes */ = { isa = PBXGroup; children = ( - 4F13E944237DD626005BCAE9 /* SwiftUI */, 4F13E945237DD62D005BCAE9 /* Models */, - 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */, + 4F13E944237DD626005BCAE9 /* SwiftUI */, 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */, + 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */, + D35055532C879DD500DCDC31 /* LoginTypeSelectionViewController.swift */, + D3848AE82C82392600A78C0A /* QrCodeScanController.swift */, ); name = Classes; sourceTree = ""; @@ -135,9 +165,11 @@ isa = PBXNativeTarget; buildConfigurationList = 4FD6C4931B754AF1002F9F90 /* Build configuration list for PBXNativeTarget "iOSNativeSwiftTemplate" */; buildPhases = ( + 469B1AB89DC48EAD107F5D36 /* [CP] Check Pods Manifest.lock */, 4FD6C4701B754AF1002F9F90 /* Sources */, 4FD6C4711B754AF1002F9F90 /* Frameworks */, 4FD6C4721B754AF1002F9F90 /* Resources */, + D39806A3A492C535683B691F /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -193,25 +225,69 @@ buildActionMask = 2147483647; files = ( 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */, + D3848AE42C82351300A78C0A /* Images.xcassets in Resources */, 4F13E943237DD5EE005BCAE9 /* userstore.json in Resources */, + D3848AE52C82351400A78C0A /* LaunchScreen.storyboard in Resources */, B77BD8A321125B510036B284 /* bootconfig.plist in Resources */, 4F13E942237DD5EE005BCAE9 /* usersyncs.json in Resources */, - CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */, - B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 469B1AB89DC48EAD107F5D36 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-iOSNativeSwiftTemplate-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + D39806A3A492C535683B691F /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 4FD6C4701B754AF1002F9F90 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */, + D3848AE92C82392600A78C0A /* QrCodeScanController.swift in Sources */, 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */, 4F13E93B237DD5D9005BCAE9 /* ContactDetailsView.swift in Sources */, 4F13E947237DD72E005BCAE9 /* AccountsListModel.swift in Sources */, + D35055542C879DD500DCDC31 /* LoginTypeSelectionViewController.swift in Sources */, 4F13E93C237DD5D9005BCAE9 /* ContactsForAccountModel.swift in Sources */, 4F13E93F237DD5D9005BCAE9 /* ContactDetailModel.swift in Sources */, 4F13E93D237DD5D9005BCAE9 /* ContactsForAccountListView.swift in Sources */, @@ -333,9 +409,11 @@ }; 4FD6C4941B754AF1002F9F90 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 42BEE51B49F5BAD7CCCD23AB /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; + DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -343,6 +421,7 @@ ); OTHER_SWIFT_FLAGS = "-DSIGNPOST_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeTemplate; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -351,15 +430,18 @@ }; 4FD6C4951B754AF1002F9F90 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 83C576D5B3530B7210E42288 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; + DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeTemplate; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift index 313cf288..fd6c7182 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift @@ -34,6 +34,9 @@ class AppDelegate : UIResponder, UIApplicationDelegate { override init() { super.init() MobileSyncSDKManager.initializeSDK() + UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { + return LoginTypeSelectionViewController() + } } // MARK: UISceneSession Lifecycle diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist index 900c1543..a170cf28 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist @@ -2,23 +2,6 @@ - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - CFBundleDevelopmentRegion en CFBundleDisplayName @@ -47,6 +30,23 @@ SFDCOAuthLoginHost login.salesforce.com + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities @@ -66,5 +66,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSCameraUsageDescription + This app requires camera usage permissions to capture QR codes for log in. diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift new file mode 100644 index 00000000..9e6c5efb --- /dev/null +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift @@ -0,0 +1,80 @@ +// +// LoginTypeSelectionViewController.swift +// iOSNativeSwiftTemplate +// +// Created by Eric Johnson on 9/3/24. +// Copyright © 2024 iOSNativeSwiftTemplateOrganizationName. All rights reserved. +// + +import Foundation +import SalesforceSDKCore +import UIKit + +/** + * Adds QR code log in to the Salesforce Mobile SDK login view. + */ +class LoginTypeSelectionViewController: SalesforceLoginViewController { + + /** A button for QR code log in */ + let loginWithQrCodeButton = UIButton() + + override func loadView() { + super.loadView() + + // Load the Log In With QR Code button. + loginWithQrCodeButton.addTarget( + self, + action: #selector(loginWithQrCodeButtonTapped), + for: .touchUpInside) + loginWithQrCodeButton.backgroundColor = UIColor.purple + loginWithQrCodeButton.setTitle("Log In With QR Code", for: .normal) + + view.addSubview(loginWithQrCodeButton) + } + + override func viewWillLayoutSubviews() { + // Intentionally blank to negate legacy super view layout. + } + + override func updateViewConstraints() { + super.updateViewConstraints() + + // Replace legacy super view layout with a comparable constraint layout including the Log In With QR Code button. + self.view.translatesAutoresizingMaskIntoConstraints = true + + if let oauthView = oauthView { + oauthView.translatesAutoresizingMaskIntoConstraints = false + oauthView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + oauthView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true + oauthView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + + if let biometricButton = self.biometricButton { + biometricButton.translatesAutoresizingMaskIntoConstraints = false + biometricButton.topAnchor.constraint(equalTo: oauthView.bottomAnchor, constant: 22.0).isActive = true + loginWithQrCodeButton.topAnchor.constraint(equalTo: biometricButton.bottomAnchor, constant: 22.0).isActive = true + } else { + loginWithQrCodeButton.topAnchor.constraint(equalTo: oauthView.bottomAnchor, constant: 22.0).isActive = true + } + + loginWithQrCodeButton.translatesAutoresizingMaskIntoConstraints = false + loginWithQrCodeButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true + loginWithQrCodeButton.heightAnchor.constraint(equalToConstant: 44.0).isActive = true + loginWithQrCodeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true + loginWithQrCodeButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -22.0).isActive = true + } + } + + @objc + func loginWithQrCodeButtonTapped(_: Any?) { + + // Present a QR code scan controller to capture the log in QR code. + let qrCodeScanController = QrCodeScanController() + qrCodeScanController.onQrCodeCaptured = { qrCodePayloadString in + + // Login using the QR code payload. + print("🤘🏻 \(qrCodePayloadString)") + let _ = self.loginFromQrCode(loginQrCodeContent: qrCodePayloadString) + } + present(qrCodeScanController, animated: true) + } +} diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift new file mode 100644 index 00000000..f931de22 --- /dev/null +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift @@ -0,0 +1,163 @@ +// +// QrCodeScanController.swift +// iOSNativeSwiftTemplate +// +// Created by Eric Johnson on 8/30/24. +// Copyright © 2024 iOSNativeSwiftTemplateOrganizationName. All rights reserved. +// + +import AVFoundation +import Foundation +import SwiftUI + +/** + * A view enabling QR code capture. + */ +class QrCodeScanController: UIViewController { + + // MARK: - View Controller Implementation + + override func viewDidLoad() { + super.viewDidLoad() + + Task { + await setupCaptureView() + } + } + + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + + // Layout the video capture preview view. + avVideoPreviewLayer?.frame = view.bounds + } + + // MARK: - QR Code Scan Controller Implementation + + /** A callback when the QR code is captured */ + var onQrCodeCaptured: ((String) -> ())? = nil + + // MARK: - QR Code Scan Controller A/V Implementation + + /** The A/V video capture preview layer used as the QR code viewfinder */ + private var avVideoPreviewLayer: AVCaptureVideoPreviewLayer? = nil + + /** + * Determines if the user has authorized camera access for this app, requested authorization from the + * user if needed. + * + * See https://developer.apple.com/documentation/avfoundation/capture_setup/requesting_authorization_to_capture_and_save_media + */ + private var isAuthorized: Bool { + get async { + // Fetch video capture authorization status. + let status = AVCaptureDevice.authorizationStatus(for: .video) + + // Determine if the user previously authorized video capture. + var isAuthorized = status == .authorized + + // If the system hasn't determined the user's authorization status, explicitly prompt them for approval. + if status == .notDetermined { + isAuthorized = await AVCaptureDevice.requestAccess(for: .video) + } + + return isAuthorized + } + } + + /** + * Sets up for image capture via the device camera and A/V foundation. + */ + private func setupCaptureView() async { + + // Review video capture authorization status. + guard await isAuthorized else { return } + + // Acquire the default video capture device. + guard let device = AVCaptureDevice.default(for: .video) else { return } + + do { + // Fetch the video capture input. + let input = try AVCaptureDeviceInput(device: device) + + let session = AVCaptureSession() + session.addInput(input) + + // Create the video capture preview view. + let avVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: session) + avVideoPreviewLayer.videoGravity = .resizeAspectFill + self.avVideoPreviewLayer = avVideoPreviewLayer + + // Create the video capture metadata output used to extract the QR code. + let output = AVCaptureMetadataOutput() + + // Create the A/V session. + session.addOutput(output) + + // Add the video capture preview view to the root view. + view.layer.addSublayer(avVideoPreviewLayer) + + // Start the A/V session. + DispatchQueue.global(qos: .background).async { + + output.setMetadataObjectsDelegate(self, queue: .main) + let x = output.availableMetadataObjectTypes + output.metadataObjectTypes = [.qr] + + session.startRunning() + } + } catch { + + // Handle A/V errors. + displayAlert() + } + } + + // MARK: - Alerts + + private func displayAlert() { + let alert = UIAlertController(title: Constants.alertTitle, + message: Constants.alertMessage, + preferredStyle: .alert) + alert.addAction(UIAlertAction(title: Constants.alertButtonTitle, + style: .default)) + present(alert, animated: true) + } + + // MARK: - Constants + + private enum Constants { + static let alertTitle = "Camera Session Error" + static let alertMessage = "Cannot scan QR codes as a camera session could not be started." + static let alertButtonTitle = "OK" + } +} + +// MARK: - A/V Capture Metadata Output Objects Delegate Implementation + +let lock = NSLock() + +extension QrCodeScanController: AVCaptureMetadataOutputObjectsDelegate { + + func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { + + guard lock.try() else { return } + + + // Guard for QR metadata objects. + guard let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject, + metadataObject.type == .qr, + let qrCodePayloadString = metadataObject.stringValue, + qrCodePayloadString.starts(with: "mobileapp://") else { return } + + // Deliver the first QR code when it is captured. + DispatchQueue.global().asyncAfter(deadline: .now() + 5) { + lock.unlock() + self.onQrCodeCaptured?(qrCodePayloadString) + self.onQrCodeCaptured = nil + } + + // Automatically dismiss. + dismiss(animated: true) + } +} diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist index f5d6f120..c069a65c 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist @@ -3,9 +3,9 @@ remoteAccessConsumerKey - 3MVG98dostKihXN53TYStBIiS8FC2a3tE3XhGId0hQ37iQjF0xe4fxMSb2mFaWZn9e3GiLs1q67TNlyRji.Xw + 3MVG9.AgwtoIvERSd8i8lePrqfnKG_MM7P9KAJ4g53iaPA4EN8zUt3__o.8YA_hCeRn_kGR.Xe9I9_pnsFuAW oauthRedirectURI - testsfdc:///mobilesdk/detect/oauth/done + mobilesdk://android/pn/tester oauthScopes web From 306949b07e6dc2333fe4d5ca188724683471d06e Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 12:36:04 -0600 Subject: [PATCH 02/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Introduce `isQrCodeLoginEnabled`. Functional P.O.C.) --- .../iOSNativeSwiftTemplate/AppDelegate.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift index fd6c7182..0abd3c4a 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift @@ -34,6 +34,10 @@ class AppDelegate : UIResponder, UIApplicationDelegate { override init() { super.init() MobileSyncSDKManager.initializeSDK() + + // Uncomment when disabling log in via Salesforce UI Bridge API generated QR codes + MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true + UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { return LoginTypeSelectionViewController() } From 808fade6108d9402d8127495cdb89ab048cfb133 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 15:32:36 -0600 Subject: [PATCH 03/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Revert `Podfile`) --- iOSNativeSwiftTemplate/Podfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iOSNativeSwiftTemplate/Podfile b/iOSNativeSwiftTemplate/Podfile index 8b1e4d46..5e7b5019 100644 --- a/iOSNativeSwiftTemplate/Podfile +++ b/iOSNativeSwiftTemplate/Podfile @@ -1,4 +1,4 @@ -require_relative '../../SalesforceMobileSDK-iOS/mobilesdk_pods' +require_relative './mobile_sdk/SalesforceMobileSDK-iOS/mobilesdk_pods' platform :ios, '16.0' @@ -14,4 +14,4 @@ post_install do |installer| signposts_post_install(installer) mobile_sdk_post_install(installer) -end +end \ No newline at end of file From 3bb386b005d704207922b4b7cd7f6ff0f119d41e Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 15:34:46 -0600 Subject: [PATCH 04/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Revert `project.pbxproj`) --- .../project.pbxproj | 114 +++--------------- 1 file changed, 16 insertions(+), 98 deletions(-) diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj index 2e95b00e..653a9efb 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj @@ -18,17 +18,13 @@ 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */; }; 4FD6C4A01B755242002F9F90 /* InitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */; }; 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */; }; - 8A7D16C2D3B653B9C7BC8413 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E4923BCE151D652A2E314ED /* Pods_iOSNativeSwiftTemplate.framework */; }; + B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */; }; B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73B520C234FA65F001B069B /* SceneDelegate.swift */; }; B77BD8A321125B510036B284 /* bootconfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = B77BD8A221125B510036B284 /* bootconfig.plist */; }; - D35055542C879DD500DCDC31 /* LoginTypeSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35055532C879DD500DCDC31 /* LoginTypeSelectionViewController.swift */; }; - D3848AE42C82351300A78C0A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3848AE22C82351300A78C0A /* Images.xcassets */; }; - D3848AE52C82351400A78C0A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D3848AE32C82351300A78C0A /* LaunchScreen.storyboard */; }; - D3848AE92C82392600A78C0A /* QrCodeScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3848AE82C82392600A78C0A /* QrCodeScanController.swift */; }; + CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEA8CA031F071B2300448B51 /* Images.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 42BEE51B49F5BAD7CCCD23AB /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.debug.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.debug.xcconfig"; sourceTree = ""; }; 4F13E936237DD5D9005BCAE9 /* ContactDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactDetailsView.swift; sourceTree = ""; }; 4F13E937237DD5D9005BCAE9 /* ContactsForAccountModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountModel.swift; sourceTree = ""; }; 4F13E938237DD5D9005BCAE9 /* ContactsForAccountListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountListView.swift; sourceTree = ""; }; @@ -43,14 +39,10 @@ 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InitialViewController.swift; sourceTree = ""; }; 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iOSNativeSwiftTemplate.entitlements; sourceTree = ""; }; 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - 83C576D5B3530B7210E42288 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.release.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.release.xcconfig"; sourceTree = ""; }; - 9E4923BCE151D652A2E314ED /* Pods_iOSNativeSwiftTemplate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOSNativeSwiftTemplate.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; B73B520C234FA65F001B069B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; B77BD8A221125B510036B284 /* bootconfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = bootconfig.plist; sourceTree = ""; }; - D35055532C879DD500DCDC31 /* LoginTypeSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginTypeSelectionViewController.swift; sourceTree = ""; }; - D3848AE22C82351300A78C0A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "../../../SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = ""; }; - D3848AE32C82351300A78C0A /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../../../SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; - D3848AE82C82392600A78C0A /* QrCodeScanController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeScanController.swift; sourceTree = ""; }; + CEA8CA031F071B2300448B51 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -58,37 +50,19 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8A7D16C2D3B653B9C7BC8413 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 231DD8297D85560CF8533961 /* Pods */ = { - isa = PBXGroup; - children = ( - 42BEE51B49F5BAD7CCCD23AB /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */, - 83C576D5B3530B7210E42288 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 38A3D00284A22BBDCDF04290 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 9E4923BCE151D652A2E314ED /* Pods_iOSNativeSwiftTemplate.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 4F13E944237DD626005BCAE9 /* SwiftUI */ = { isa = PBXGroup; children = ( + B73B520C234FA65F001B069B /* SceneDelegate.swift */, 4F13E939237DD5D9005BCAE9 /* AccountsListView.swift */, - 4F13E936237DD5D9005BCAE9 /* ContactDetailsView.swift */, 4F13E938237DD5D9005BCAE9 /* ContactsForAccountListView.swift */, - B73B520C234FA65F001B069B /* SceneDelegate.swift */, + 4F13E936237DD5D9005BCAE9 /* ContactDetailsView.swift */, ); name = SwiftUI; sourceTree = ""; @@ -97,8 +71,8 @@ isa = PBXGroup; children = ( 4F13E946237DD72E005BCAE9 /* AccountsListModel.swift */, - 4F13E93A237DD5D9005BCAE9 /* ContactDetailModel.swift */, 4F13E937237DD5D9005BCAE9 /* ContactsForAccountModel.swift */, + 4F13E93A237DD5D9005BCAE9 /* ContactDetailModel.swift */, ); name = Models; sourceTree = ""; @@ -106,9 +80,7 @@ 4FD6C46B1B754AF1002F9F90 = { isa = PBXGroup; children = ( - 38A3D00284A22BBDCDF04290 /* Frameworks */, 4FD6C4761B754AF1002F9F90 /* iOSNativeSwiftTemplate */, - 231DD8297D85560CF8533961 /* Pods */, 4FD6C4751B754AF1002F9F90 /* Products */, ); sourceTree = ""; @@ -124,9 +96,9 @@ 4FD6C4761B754AF1002F9F90 /* iOSNativeSwiftTemplate */ = { isa = PBXGroup; children = ( + 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */, 4FD6C4A11B755265002F9F90 /* Classes */, 4FD6C4771B754AF1002F9F90 /* Supporting Files */, - 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */, ); path = iOSNativeSwiftTemplate; sourceTree = ""; @@ -134,13 +106,13 @@ 4FD6C4771B754AF1002F9F90 /* Supporting Files */ = { isa = PBXGroup; children = ( - B77BD8A221125B510036B284 /* bootconfig.plist */, - D3848AE22C82351300A78C0A /* Images.xcassets */, - 4FD6C4781B754AF1002F9F90 /* Info.plist */, - D3848AE32C82351300A78C0A /* LaunchScreen.storyboard */, 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */, 4F13E941237DD5EE005BCAE9 /* userstore.json */, 4F13E940237DD5EE005BCAE9 /* usersyncs.json */, + B77BD8A221125B510036B284 /* bootconfig.plist */, + B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */, + CEA8CA031F071B2300448B51 /* Images.xcassets */, + 4FD6C4781B754AF1002F9F90 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; @@ -148,12 +120,10 @@ 4FD6C4A11B755265002F9F90 /* Classes */ = { isa = PBXGroup; children = ( - 4F13E945237DD62D005BCAE9 /* Models */, 4F13E944237DD626005BCAE9 /* SwiftUI */, - 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */, + 4F13E945237DD62D005BCAE9 /* Models */, 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */, - D35055532C879DD500DCDC31 /* LoginTypeSelectionViewController.swift */, - D3848AE82C82392600A78C0A /* QrCodeScanController.swift */, + 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */, ); name = Classes; sourceTree = ""; @@ -165,11 +135,9 @@ isa = PBXNativeTarget; buildConfigurationList = 4FD6C4931B754AF1002F9F90 /* Build configuration list for PBXNativeTarget "iOSNativeSwiftTemplate" */; buildPhases = ( - 469B1AB89DC48EAD107F5D36 /* [CP] Check Pods Manifest.lock */, 4FD6C4701B754AF1002F9F90 /* Sources */, 4FD6C4711B754AF1002F9F90 /* Frameworks */, 4FD6C4721B754AF1002F9F90 /* Resources */, - D39806A3A492C535683B691F /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -225,69 +193,25 @@ buildActionMask = 2147483647; files = ( 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */, - D3848AE42C82351300A78C0A /* Images.xcassets in Resources */, 4F13E943237DD5EE005BCAE9 /* userstore.json in Resources */, - D3848AE52C82351400A78C0A /* LaunchScreen.storyboard in Resources */, B77BD8A321125B510036B284 /* bootconfig.plist in Resources */, 4F13E942237DD5EE005BCAE9 /* usersyncs.json in Resources */, + CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */, + B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 469B1AB89DC48EAD107F5D36 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-iOSNativeSwiftTemplate-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - D39806A3A492C535683B691F /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 4FD6C4701B754AF1002F9F90 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */, - D3848AE92C82392600A78C0A /* QrCodeScanController.swift in Sources */, 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */, 4F13E93B237DD5D9005BCAE9 /* ContactDetailsView.swift in Sources */, 4F13E947237DD72E005BCAE9 /* AccountsListModel.swift in Sources */, - D35055542C879DD500DCDC31 /* LoginTypeSelectionViewController.swift in Sources */, 4F13E93C237DD5D9005BCAE9 /* ContactsForAccountModel.swift in Sources */, 4F13E93F237DD5D9005BCAE9 /* ContactDetailModel.swift in Sources */, 4F13E93D237DD5D9005BCAE9 /* ContactsForAccountListView.swift in Sources */, @@ -409,11 +333,9 @@ }; 4FD6C4941B754AF1002F9F90 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 42BEE51B49F5BAD7CCCD23AB /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; - DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -421,7 +343,6 @@ ); OTHER_SWIFT_FLAGS = "-DSIGNPOST_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeTemplate; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -430,18 +351,15 @@ }; 4FD6C4951B754AF1002F9F90 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 83C576D5B3530B7210E42288 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; - DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeTemplate; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; From 3b0e03aa225bfe1d9c2e1e45f4caa0156e59c653 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 15:56:53 -0600 Subject: [PATCH 05/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Self Review Cleanup, Pt. 1) --- .../project.pbxproj | 12 ++++++-- .../iOSNativeSwiftTemplate/AppDelegate.swift | 9 +++--- .../LoginTypeSelectionViewController.swift | 30 +++++++++++++++---- .../QrCodeScanController.swift | 29 ++++++++++++++---- 4 files changed, 62 insertions(+), 18 deletions(-) diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj index 653a9efb..13d9fa6a 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73B520C234FA65F001B069B /* SceneDelegate.swift */; }; B77BD8A321125B510036B284 /* bootconfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = B77BD8A221125B510036B284 /* bootconfig.plist */; }; CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEA8CA031F071B2300448B51 /* Images.xcassets */; }; + D322A61B2C9E2471001F8453 /* QrCodeScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D322A6192C9E2471001F8453 /* QrCodeScanController.swift */; }; + D322A61C2C9E2471001F8453 /* LoginTypeSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -43,6 +45,8 @@ B73B520C234FA65F001B069B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; B77BD8A221125B510036B284 /* bootconfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = bootconfig.plist; sourceTree = ""; }; CEA8CA031F071B2300448B51 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = SOURCE_ROOT; }; + D322A6192C9E2471001F8453 /* QrCodeScanController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QrCodeScanController.swift; sourceTree = ""; }; + D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginTypeSelectionViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -120,10 +124,12 @@ 4FD6C4A11B755265002F9F90 /* Classes */ = { isa = PBXGroup; children = ( - 4F13E944237DD626005BCAE9 /* SwiftUI */, 4F13E945237DD62D005BCAE9 /* Models */, - 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */, + 4F13E944237DD626005BCAE9 /* SwiftUI */, 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */, + 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */, + D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */, + D322A6192C9E2471001F8453 /* QrCodeScanController.swift */, ); name = Classes; sourceTree = ""; @@ -212,10 +218,12 @@ 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */, 4F13E93B237DD5D9005BCAE9 /* ContactDetailsView.swift in Sources */, 4F13E947237DD72E005BCAE9 /* AccountsListModel.swift in Sources */, + D322A61B2C9E2471001F8453 /* QrCodeScanController.swift in Sources */, 4F13E93C237DD5D9005BCAE9 /* ContactsForAccountModel.swift in Sources */, 4F13E93F237DD5D9005BCAE9 /* ContactDetailModel.swift in Sources */, 4F13E93D237DD5D9005BCAE9 /* ContactsForAccountListView.swift in Sources */, 4F13E93E237DD5D9005BCAE9 /* AccountsListView.swift in Sources */, + D322A61C2C9E2471001F8453 /* LoginTypeSelectionViewController.swift in Sources */, 4FD6C4A01B755242002F9F90 /* InitialViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift index 0abd3c4a..41bb268f 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift @@ -36,11 +36,10 @@ class AppDelegate : UIResponder, UIApplicationDelegate { MobileSyncSDKManager.initializeSDK() // Uncomment when disabling log in via Salesforce UI Bridge API generated QR codes - MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true - - UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { - return LoginTypeSelectionViewController() - } + // MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true + // UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { + // return LoginTypeSelectionViewController() + // } } // MARK: UISceneSession Lifecycle diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift index 9e6c5efb..3ae08e02 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift @@ -3,8 +3,28 @@ // iOSNativeSwiftTemplate // // Created by Eric Johnson on 9/3/24. -// Copyright © 2024 iOSNativeSwiftTemplateOrganizationName. All rights reserved. // +// Copyright (c) 2024-present, salesforce.com, inc. All rights reserved. +// +// Redistribution and use of this software in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, this list of conditions +// and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission of salesforce.com, inc. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import Foundation import SalesforceSDKCore @@ -26,7 +46,6 @@ class LoginTypeSelectionViewController: SalesforceLoginViewController { self, action: #selector(loginWithQrCodeButtonTapped), for: .touchUpInside) - loginWithQrCodeButton.backgroundColor = UIColor.purple loginWithQrCodeButton.setTitle("Log In With QR Code", for: .normal) view.addSubview(loginWithQrCodeButton) @@ -40,7 +59,7 @@ class LoginTypeSelectionViewController: SalesforceLoginViewController { super.updateViewConstraints() // Replace legacy super view layout with a comparable constraint layout including the Log In With QR Code button. - self.view.translatesAutoresizingMaskIntoConstraints = true + view.translatesAutoresizingMaskIntoConstraints = true if let oauthView = oauthView { oauthView.translatesAutoresizingMaskIntoConstraints = false @@ -48,7 +67,7 @@ class LoginTypeSelectionViewController: SalesforceLoginViewController { oauthView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true oauthView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true - if let biometricButton = self.biometricButton { + if let biometricButton = biometricButton { biometricButton.translatesAutoresizingMaskIntoConstraints = false biometricButton.topAnchor.constraint(equalTo: oauthView.bottomAnchor, constant: 22.0).isActive = true loginWithQrCodeButton.topAnchor.constraint(equalTo: biometricButton.bottomAnchor, constant: 22.0).isActive = true @@ -72,8 +91,7 @@ class LoginTypeSelectionViewController: SalesforceLoginViewController { qrCodeScanController.onQrCodeCaptured = { qrCodePayloadString in // Login using the QR code payload. - print("🤘🏻 \(qrCodePayloadString)") - let _ = self.loginFromQrCode(loginQrCodeContent: qrCodePayloadString) + let _ = loginFromQrCode(loginQrCodeContent: qrCodePayloadString) } present(qrCodeScanController, animated: true) } diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift index f931de22..544b6d9d 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift @@ -3,8 +3,28 @@ // iOSNativeSwiftTemplate // // Created by Eric Johnson on 8/30/24. -// Copyright © 2024 iOSNativeSwiftTemplateOrganizationName. All rights reserved. // +// Copyright (c) 2024-present, salesforce.com, inc. All rights reserved. +// +// Redistribution and use of this software in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, this list of conditions +// and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission of salesforce.com, inc. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import AVFoundation import Foundation @@ -80,6 +100,7 @@ class QrCodeScanController: UIViewController { // Fetch the video capture input. let input = try AVCaptureDeviceInput(device: device) + // Create the A/V session. let session = AVCaptureSession() session.addInput(input) @@ -90,8 +111,6 @@ class QrCodeScanController: UIViewController { // Create the video capture metadata output used to extract the QR code. let output = AVCaptureMetadataOutput() - - // Create the A/V session. session.addOutput(output) // Add the video capture preview view to the root view. @@ -100,8 +119,8 @@ class QrCodeScanController: UIViewController { // Start the A/V session. DispatchQueue.global(qos: .background).async { + // Configure the video capture metadata output. output.setMetadataObjectsDelegate(self, queue: .main) - let x = output.availableMetadataObjectTypes output.metadataObjectTypes = [.qr] session.startRunning() @@ -135,7 +154,7 @@ class QrCodeScanController: UIViewController { // MARK: - A/V Capture Metadata Output Objects Delegate Implementation -let lock = NSLock() +fileprivate let lock = NSLock() extension QrCodeScanController: AVCaptureMetadataOutputObjectsDelegate { From b6825f934e6a0c699879c16f45437d49b8fdacdd Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 16:05:30 -0600 Subject: [PATCH 06/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Self Review Cleanup, Pt. 2) --- .../LoginTypeSelectionViewController.swift | 2 +- .../iOSNativeSwiftTemplate/QrCodeScanController.swift | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift index 3ae08e02..bb16a466 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift @@ -91,7 +91,7 @@ class LoginTypeSelectionViewController: SalesforceLoginViewController { qrCodeScanController.onQrCodeCaptured = { qrCodePayloadString in // Login using the QR code payload. - let _ = loginFromQrCode(loginQrCodeContent: qrCodePayloadString) + let _ = self.loginFromQrCode(loginQrCodeContent: qrCodePayloadString) } present(qrCodeScanController, animated: true) } diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift index 544b6d9d..35c44130 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/QrCodeScanController.swift @@ -154,14 +154,14 @@ class QrCodeScanController: UIViewController { // MARK: - A/V Capture Metadata Output Objects Delegate Implementation -fileprivate let lock = NSLock() +/** A lock to ensure only a single QR code is captured. */ +fileprivate let onQrCodeCaptureLock = NSLock() extension QrCodeScanController: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { - guard lock.try() else { return } - + guard onQrCodeCaptureLock.try() else { return } // Guard for QR metadata objects. guard let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject, @@ -170,8 +170,8 @@ extension QrCodeScanController: AVCaptureMetadataOutputObjectsDelegate { qrCodePayloadString.starts(with: "mobileapp://") else { return } // Deliver the first QR code when it is captured. - DispatchQueue.global().asyncAfter(deadline: .now() + 5) { - lock.unlock() + DispatchQueue.global().async { + onQrCodeCaptureLock.unlock() self.onQrCodeCaptured?(qrCodePayloadString) self.onQrCodeCaptured = nil } From 316c1625c26b18bf01cb2efbbbcfee98aa6bc91a Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 16:05:57 -0600 Subject: [PATCH 07/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Revert `bootconfig.plist`) --- .../iOSNativeSwiftTemplate/bootconfig.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist index c069a65c..f5d6f120 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist @@ -3,9 +3,9 @@ remoteAccessConsumerKey - 3MVG9.AgwtoIvERSd8i8lePrqfnKG_MM7P9KAJ4g53iaPA4EN8zUt3__o.8YA_hCeRn_kGR.Xe9I9_pnsFuAW + 3MVG98dostKihXN53TYStBIiS8FC2a3tE3XhGId0hQ37iQjF0xe4fxMSb2mFaWZn9e3GiLs1q67TNlyRji.Xw oauthRedirectURI - mobilesdk://android/pn/tester + testsfdc:///mobilesdk/detect/oauth/done oauthScopes web From 4648437038296bee72da2d24fb1fdee020f4343d Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Mon, 23 Sep 2024 14:58:49 -0600 Subject: [PATCH 08/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Improve Button Layouts) --- iOSNativeSwiftTemplate/Podfile | 4 +- .../project.pbxproj | 91 +++++++++++++++++-- .../iOSNativeSwiftTemplate/AppDelegate.swift | 8 +- .../iOSNativeSwiftTemplate/Info.plist | 4 +- .../LoginTypeSelectionViewController.swift | 11 ++- .../iOSNativeSwiftTemplate/bootconfig.plist | 4 +- 6 files changed, 102 insertions(+), 20 deletions(-) diff --git a/iOSNativeSwiftTemplate/Podfile b/iOSNativeSwiftTemplate/Podfile index 5e7b5019..8b1e4d46 100644 --- a/iOSNativeSwiftTemplate/Podfile +++ b/iOSNativeSwiftTemplate/Podfile @@ -1,4 +1,4 @@ -require_relative './mobile_sdk/SalesforceMobileSDK-iOS/mobilesdk_pods' +require_relative '../../SalesforceMobileSDK-iOS/mobilesdk_pods' platform :ios, '16.0' @@ -14,4 +14,4 @@ post_install do |installer| signposts_post_install(installer) mobile_sdk_post_install(installer) -end \ No newline at end of file +end diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj index 13d9fa6a..c1bc6a59 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj @@ -18,15 +18,18 @@ 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */; }; 4FD6C4A01B755242002F9F90 /* InitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */; }; 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */; }; - B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */; }; + 96DA78A26C5F837CAFBCDA18 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 761909FDDB7AF84F4909F94E /* Pods_iOSNativeSwiftTemplate.framework */; }; B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73B520C234FA65F001B069B /* SceneDelegate.swift */; }; B77BD8A321125B510036B284 /* bootconfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = B77BD8A221125B510036B284 /* bootconfig.plist */; }; - CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEA8CA031F071B2300448B51 /* Images.xcassets */; }; D322A61B2C9E2471001F8453 /* QrCodeScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D322A6192C9E2471001F8453 /* QrCodeScanController.swift */; }; D322A61C2C9E2471001F8453 /* LoginTypeSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */; }; + D322A61F2C9E276E001F8453 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D322A61D2C9E276E001F8453 /* Images.xcassets */; }; + D322A6202C9E276E001F8453 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D322A61E2C9E276E001F8453 /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 04E2305AC10D65D17D80DF60 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.release.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.release.xcconfig"; sourceTree = ""; }; + 0FEBAE0F50CDBC23E1D48FF4 /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.debug.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.debug.xcconfig"; sourceTree = ""; }; 4F13E936237DD5D9005BCAE9 /* ContactDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactDetailsView.swift; sourceTree = ""; }; 4F13E937237DD5D9005BCAE9 /* ContactsForAccountModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountModel.swift; sourceTree = ""; }; 4F13E938237DD5D9005BCAE9 /* ContactsForAccountListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountListView.swift; sourceTree = ""; }; @@ -41,12 +44,13 @@ 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InitialViewController.swift; sourceTree = ""; }; 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iOSNativeSwiftTemplate.entitlements; sourceTree = ""; }; 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; + 761909FDDB7AF84F4909F94E /* Pods_iOSNativeSwiftTemplate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOSNativeSwiftTemplate.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B73B520C234FA65F001B069B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; B77BD8A221125B510036B284 /* bootconfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = bootconfig.plist; sourceTree = ""; }; - CEA8CA031F071B2300448B51 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = SOURCE_ROOT; }; D322A6192C9E2471001F8453 /* QrCodeScanController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QrCodeScanController.swift; sourceTree = ""; }; D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginTypeSelectionViewController.swift; sourceTree = ""; }; + D322A61D2C9E276E001F8453 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "../../../SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = ""; }; + D322A61E2C9E276E001F8453 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../../../SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,12 +58,21 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 96DA78A26C5F837CAFBCDA18 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 10A8D5451CB473C2F4EDC8AC /* Frameworks */ = { + isa = PBXGroup; + children = ( + 761909FDDB7AF84F4909F94E /* Pods_iOSNativeSwiftTemplate.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 4F13E944237DD626005BCAE9 /* SwiftUI */ = { isa = PBXGroup; children = ( @@ -86,6 +99,8 @@ children = ( 4FD6C4761B754AF1002F9F90 /* iOSNativeSwiftTemplate */, 4FD6C4751B754AF1002F9F90 /* Products */, + E7F574B7A060F1E98830E13C /* Pods */, + 10A8D5451CB473C2F4EDC8AC /* Frameworks */, ); sourceTree = ""; }; @@ -110,12 +125,12 @@ 4FD6C4771B754AF1002F9F90 /* Supporting Files */ = { isa = PBXGroup; children = ( + D322A61D2C9E276E001F8453 /* Images.xcassets */, + D322A61E2C9E276E001F8453 /* LaunchScreen.storyboard */, 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */, 4F13E941237DD5EE005BCAE9 /* userstore.json */, 4F13E940237DD5EE005BCAE9 /* usersyncs.json */, B77BD8A221125B510036B284 /* bootconfig.plist */, - B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */, - CEA8CA031F071B2300448B51 /* Images.xcassets */, 4FD6C4781B754AF1002F9F90 /* Info.plist */, ); name = "Supporting Files"; @@ -134,6 +149,16 @@ name = Classes; sourceTree = ""; }; + E7F574B7A060F1E98830E13C /* Pods */ = { + isa = PBXGroup; + children = ( + 0FEBAE0F50CDBC23E1D48FF4 /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */, + 04E2305AC10D65D17D80DF60 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -141,9 +166,11 @@ isa = PBXNativeTarget; buildConfigurationList = 4FD6C4931B754AF1002F9F90 /* Build configuration list for PBXNativeTarget "iOSNativeSwiftTemplate" */; buildPhases = ( + C8758747059070ECA4C1FAA1 /* [CP] Check Pods Manifest.lock */, 4FD6C4701B754AF1002F9F90 /* Sources */, 4FD6C4711B754AF1002F9F90 /* Frameworks */, 4FD6C4721B754AF1002F9F90 /* Resources */, + 09AACF901317746B37188A7B /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -199,16 +226,58 @@ buildActionMask = 2147483647; files = ( 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */, + D322A61F2C9E276E001F8453 /* Images.xcassets in Resources */, 4F13E943237DD5EE005BCAE9 /* userstore.json in Resources */, + D322A6202C9E276E001F8453 /* LaunchScreen.storyboard in Resources */, B77BD8A321125B510036B284 /* bootconfig.plist in Resources */, 4F13E942237DD5EE005BCAE9 /* usersyncs.json in Resources */, - CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */, - B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 09AACF901317746B37188A7B /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C8758747059070ECA4C1FAA1 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-iOSNativeSwiftTemplate-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 4FD6C4701B754AF1002F9F90 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -341,9 +410,11 @@ }; 4FD6C4941B754AF1002F9F90 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0FEBAE0F50CDBC23E1D48FF4 /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; + DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -351,6 +422,7 @@ ); OTHER_SWIFT_FLAGS = "-DSIGNPOST_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeSwift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -359,15 +431,18 @@ }; 4FD6C4951B754AF1002F9F90 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 04E2305AC10D65D17D80DF60 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; + DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; + "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeSwift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift index 41bb268f..8c74656b 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift @@ -36,10 +36,10 @@ class AppDelegate : UIResponder, UIApplicationDelegate { MobileSyncSDKManager.initializeSDK() // Uncomment when disabling log in via Salesforce UI Bridge API generated QR codes - // MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true - // UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { - // return LoginTypeSelectionViewController() - // } + MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true + UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { + return LoginTypeSelectionViewController() + } } // MARK: UISceneSession Lifecycle diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist index a170cf28..4b8e049c 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/Info.plist @@ -28,6 +28,8 @@ 1.0 LSRequiresIPhoneOS + NSCameraUsageDescription + This app requires camera usage permissions to capture QR codes for log in. SFDCOAuthLoginHost login.salesforce.com UIApplicationSceneManifest @@ -66,7 +68,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - NSCameraUsageDescription - This app requires camera usage permissions to capture QR codes for log in. diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift index bb16a466..d6f3156a 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/LoginTypeSelectionViewController.swift @@ -46,7 +46,7 @@ class LoginTypeSelectionViewController: SalesforceLoginViewController { self, action: #selector(loginWithQrCodeButtonTapped), for: .touchUpInside) - loginWithQrCodeButton.setTitle("Log In With QR Code", for: .normal) + loginWithQrCodeButton.setTitle("Log In with QR Code", for: .normal) view.addSubview(loginWithQrCodeButton) } @@ -68,15 +68,22 @@ class LoginTypeSelectionViewController: SalesforceLoginViewController { oauthView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true if let biometricButton = biometricButton { + biometricButton.layer.borderColor = UIColor.white.cgColor + biometricButton.layer.borderWidth = 2.0 biometricButton.translatesAutoresizingMaskIntoConstraints = false biometricButton.topAnchor.constraint(equalTo: oauthView.bottomAnchor, constant: 22.0).isActive = true + biometricButton.widthAnchor.constraint(equalToConstant: 250.0).isActive = true + biometricButton.heightAnchor.constraint(equalToConstant: 44.0).isActive = true + biometricButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true loginWithQrCodeButton.topAnchor.constraint(equalTo: biometricButton.bottomAnchor, constant: 22.0).isActive = true } else { loginWithQrCodeButton.topAnchor.constraint(equalTo: oauthView.bottomAnchor, constant: 22.0).isActive = true } + loginWithQrCodeButton.layer.borderColor = UIColor.white.cgColor + loginWithQrCodeButton.layer.borderWidth = 2.0 loginWithQrCodeButton.translatesAutoresizingMaskIntoConstraints = false - loginWithQrCodeButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true + loginWithQrCodeButton.widthAnchor.constraint(equalToConstant: 250.0).isActive = true loginWithQrCodeButton.heightAnchor.constraint(equalToConstant: 44.0).isActive = true loginWithQrCodeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true loginWithQrCodeButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -22.0).isActive = true diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist index f5d6f120..c069a65c 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist @@ -3,9 +3,9 @@ remoteAccessConsumerKey - 3MVG98dostKihXN53TYStBIiS8FC2a3tE3XhGId0hQ37iQjF0xe4fxMSb2mFaWZn9e3GiLs1q67TNlyRji.Xw + 3MVG9.AgwtoIvERSd8i8lePrqfnKG_MM7P9KAJ4g53iaPA4EN8zUt3__o.8YA_hCeRn_kGR.Xe9I9_pnsFuAW oauthRedirectURI - testsfdc:///mobilesdk/detect/oauth/done + mobilesdk://android/pn/tester oauthScopes web From 56983fea1ede7ba458c93fc2955964c32b71567e Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Thu, 26 Sep 2024 15:49:45 -0600 Subject: [PATCH 09/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Revert Local Diagnostics) --- iOSNativeSwiftTemplate/Podfile | 4 +- .../project.pbxproj | 111 +++--------------- .../iOSNativeSwiftTemplate/AppDelegate.swift | 8 +- .../iOSNativeSwiftTemplate/bootconfig.plist | 4 +- 4 files changed, 26 insertions(+), 101 deletions(-) diff --git a/iOSNativeSwiftTemplate/Podfile b/iOSNativeSwiftTemplate/Podfile index 8b1e4d46..5e7b5019 100644 --- a/iOSNativeSwiftTemplate/Podfile +++ b/iOSNativeSwiftTemplate/Podfile @@ -1,4 +1,4 @@ -require_relative '../../SalesforceMobileSDK-iOS/mobilesdk_pods' +require_relative './mobile_sdk/SalesforceMobileSDK-iOS/mobilesdk_pods' platform :ios, '16.0' @@ -14,4 +14,4 @@ post_install do |installer| signposts_post_install(installer) mobile_sdk_post_install(installer) -end +end \ No newline at end of file diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj index c1bc6a59..0c69fb45 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.xcodeproj/project.pbxproj @@ -18,18 +18,15 @@ 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */; }; 4FD6C4A01B755242002F9F90 /* InitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */; }; 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */; }; - 96DA78A26C5F837CAFBCDA18 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 761909FDDB7AF84F4909F94E /* Pods_iOSNativeSwiftTemplate.framework */; }; + B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */; }; B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73B520C234FA65F001B069B /* SceneDelegate.swift */; }; B77BD8A321125B510036B284 /* bootconfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = B77BD8A221125B510036B284 /* bootconfig.plist */; }; - D322A61B2C9E2471001F8453 /* QrCodeScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D322A6192C9E2471001F8453 /* QrCodeScanController.swift */; }; - D322A61C2C9E2471001F8453 /* LoginTypeSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */; }; - D322A61F2C9E276E001F8453 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D322A61D2C9E276E001F8453 /* Images.xcassets */; }; - D322A6202C9E276E001F8453 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D322A61E2C9E276E001F8453 /* LaunchScreen.storyboard */; }; + CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEA8CA031F071B2300448B51 /* Images.xcassets */; }; + D33B88412CA60F0E00892D80 /* LoginTypeSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33B883F2CA60F0E00892D80 /* LoginTypeSelectionViewController.swift */; }; + D33B88422CA60F0E00892D80 /* QrCodeScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33B88402CA60F0E00892D80 /* QrCodeScanController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 04E2305AC10D65D17D80DF60 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.release.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.release.xcconfig"; sourceTree = ""; }; - 0FEBAE0F50CDBC23E1D48FF4 /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOSNativeSwiftTemplate.debug.xcconfig"; path = "Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate.debug.xcconfig"; sourceTree = ""; }; 4F13E936237DD5D9005BCAE9 /* ContactDetailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactDetailsView.swift; sourceTree = ""; }; 4F13E937237DD5D9005BCAE9 /* ContactsForAccountModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountModel.swift; sourceTree = ""; }; 4F13E938237DD5D9005BCAE9 /* ContactsForAccountListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactsForAccountListView.swift; sourceTree = ""; }; @@ -44,13 +41,12 @@ 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InitialViewController.swift; sourceTree = ""; }; 4FF12F8A1DCA91F5004D9EF9 /* iOSNativeSwiftTemplate.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iOSNativeSwiftTemplate.entitlements; sourceTree = ""; }; 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - 761909FDDB7AF84F4909F94E /* Pods_iOSNativeSwiftTemplate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOSNativeSwiftTemplate.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; B73B520C234FA65F001B069B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; B77BD8A221125B510036B284 /* bootconfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = bootconfig.plist; sourceTree = ""; }; - D322A6192C9E2471001F8453 /* QrCodeScanController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QrCodeScanController.swift; sourceTree = ""; }; - D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginTypeSelectionViewController.swift; sourceTree = ""; }; - D322A61D2C9E276E001F8453 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "../../../SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = ""; }; - D322A61E2C9E276E001F8453 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = "../../../SalesforceMobileSDK-iOS/shared/resources/LaunchScreen.storyboard"; sourceTree = ""; }; + CEA8CA031F071B2300448B51 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "mobile_sdk/SalesforceMobileSDK-iOS/shared/resources/Images.xcassets"; sourceTree = SOURCE_ROOT; }; + D33B883F2CA60F0E00892D80 /* LoginTypeSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginTypeSelectionViewController.swift; sourceTree = ""; }; + D33B88402CA60F0E00892D80 /* QrCodeScanController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QrCodeScanController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -58,21 +54,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 96DA78A26C5F837CAFBCDA18 /* Pods_iOSNativeSwiftTemplate.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 10A8D5451CB473C2F4EDC8AC /* Frameworks */ = { - isa = PBXGroup; - children = ( - 761909FDDB7AF84F4909F94E /* Pods_iOSNativeSwiftTemplate.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 4F13E944237DD626005BCAE9 /* SwiftUI */ = { isa = PBXGroup; children = ( @@ -99,8 +86,6 @@ children = ( 4FD6C4761B754AF1002F9F90 /* iOSNativeSwiftTemplate */, 4FD6C4751B754AF1002F9F90 /* Products */, - E7F574B7A060F1E98830E13C /* Pods */, - 10A8D5451CB473C2F4EDC8AC /* Frameworks */, ); sourceTree = ""; }; @@ -125,12 +110,12 @@ 4FD6C4771B754AF1002F9F90 /* Supporting Files */ = { isa = PBXGroup; children = ( - D322A61D2C9E276E001F8453 /* Images.xcassets */, - D322A61E2C9E276E001F8453 /* LaunchScreen.storyboard */, 69B48C312AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy */, 4F13E941237DD5EE005BCAE9 /* userstore.json */, 4F13E940237DD5EE005BCAE9 /* usersyncs.json */, B77BD8A221125B510036B284 /* bootconfig.plist */, + B7168FBB1FACC6F900A48DB5 /* LaunchScreen.storyboard */, + CEA8CA031F071B2300448B51 /* Images.xcassets */, 4FD6C4781B754AF1002F9F90 /* Info.plist */, ); name = "Supporting Files"; @@ -139,26 +124,16 @@ 4FD6C4A11B755265002F9F90 /* Classes */ = { isa = PBXGroup; children = ( - 4F13E945237DD62D005BCAE9 /* Models */, + D33B883F2CA60F0E00892D80 /* LoginTypeSelectionViewController.swift */, + D33B88402CA60F0E00892D80 /* QrCodeScanController.swift */, 4F13E944237DD626005BCAE9 /* SwiftUI */, - 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */, + 4F13E945237DD62D005BCAE9 /* Models */, 4FD6C49D1B755242002F9F90 /* InitialViewController.swift */, - D322A61A2C9E2471001F8453 /* LoginTypeSelectionViewController.swift */, - D322A6192C9E2471001F8453 /* QrCodeScanController.swift */, + 4FD6C4791B754AF1002F9F90 /* AppDelegate.swift */, ); name = Classes; sourceTree = ""; }; - E7F574B7A060F1E98830E13C /* Pods */ = { - isa = PBXGroup; - children = ( - 0FEBAE0F50CDBC23E1D48FF4 /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */, - 04E2305AC10D65D17D80DF60 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -166,11 +141,9 @@ isa = PBXNativeTarget; buildConfigurationList = 4FD6C4931B754AF1002F9F90 /* Build configuration list for PBXNativeTarget "iOSNativeSwiftTemplate" */; buildPhases = ( - C8758747059070ECA4C1FAA1 /* [CP] Check Pods Manifest.lock */, 4FD6C4701B754AF1002F9F90 /* Sources */, 4FD6C4711B754AF1002F9F90 /* Frameworks */, 4FD6C4721B754AF1002F9F90 /* Resources */, - 09AACF901317746B37188A7B /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -226,73 +199,31 @@ buildActionMask = 2147483647; files = ( 69B48C322AD4E7AD0026AEC6 /* PrivacyInfo.xcprivacy in Resources */, - D322A61F2C9E276E001F8453 /* Images.xcassets in Resources */, 4F13E943237DD5EE005BCAE9 /* userstore.json in Resources */, - D322A6202C9E276E001F8453 /* LaunchScreen.storyboard in Resources */, B77BD8A321125B510036B284 /* bootconfig.plist in Resources */, 4F13E942237DD5EE005BCAE9 /* usersyncs.json in Resources */, + CEA8CA041F071B2300448B51 /* Images.xcassets in Resources */, + B7168FBC1FACC6F900A48DB5 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 09AACF901317746B37188A7B /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOSNativeSwiftTemplate/Pods-iOSNativeSwiftTemplate-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - C8758747059070ECA4C1FAA1 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-iOSNativeSwiftTemplate-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 4FD6C4701B754AF1002F9F90 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B73B520D234FA65F001B069B /* SceneDelegate.swift in Sources */, + D33B88422CA60F0E00892D80 /* QrCodeScanController.swift in Sources */, 4FD6C47A1B754AF1002F9F90 /* AppDelegate.swift in Sources */, 4F13E93B237DD5D9005BCAE9 /* ContactDetailsView.swift in Sources */, + D33B88412CA60F0E00892D80 /* LoginTypeSelectionViewController.swift in Sources */, 4F13E947237DD72E005BCAE9 /* AccountsListModel.swift in Sources */, - D322A61B2C9E2471001F8453 /* QrCodeScanController.swift in Sources */, 4F13E93C237DD5D9005BCAE9 /* ContactsForAccountModel.swift in Sources */, 4F13E93F237DD5D9005BCAE9 /* ContactDetailModel.swift in Sources */, 4F13E93D237DD5D9005BCAE9 /* ContactsForAccountListView.swift in Sources */, 4F13E93E237DD5D9005BCAE9 /* AccountsListView.swift in Sources */, - D322A61C2C9E2471001F8453 /* LoginTypeSelectionViewController.swift in Sources */, 4FD6C4A01B755242002F9F90 /* InitialViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -410,11 +341,9 @@ }; 4FD6C4941B754AF1002F9F90 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0FEBAE0F50CDBC23E1D48FF4 /* Pods-iOSNativeSwiftTemplate.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; - DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -422,7 +351,6 @@ ); OTHER_SWIFT_FLAGS = "-DSIGNPOST_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeSwift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -431,18 +359,15 @@ }; 4FD6C4951B754AF1002F9F90 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 04E2305AC10D65D17D80DF60 /* Pods-iOSNativeSwiftTemplate.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = iOSNativeSwiftTemplate/iOSNativeSwiftTemplate.entitlements; - DEVELOPMENT_TEAM = XD7TD9S6ZU; INFOPLIST_FILE = iOSNativeSwiftTemplate/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.salesforce.${PRODUCT_NAME:rfc1034identifier}"; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.salesforce.iOSNativeSwift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "iOSNativeSwiftTemplate/Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift index 8c74656b..e9891710 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift @@ -36,10 +36,10 @@ class AppDelegate : UIResponder, UIApplicationDelegate { MobileSyncSDKManager.initializeSDK() // Uncomment when disabling log in via Salesforce UI Bridge API generated QR codes - MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true - UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { - return LoginTypeSelectionViewController() - } + //MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true + //UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { + // return LoginTypeSelectionViewController() + //} } // MARK: UISceneSession Lifecycle diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist index c069a65c..f5d6f120 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/bootconfig.plist @@ -3,9 +3,9 @@ remoteAccessConsumerKey - 3MVG9.AgwtoIvERSd8i8lePrqfnKG_MM7P9KAJ4g53iaPA4EN8zUt3__o.8YA_hCeRn_kGR.Xe9I9_pnsFuAW + 3MVG98dostKihXN53TYStBIiS8FC2a3tE3XhGId0hQ37iQjF0xe4fxMSb2mFaWZn9e3GiLs1q67TNlyRji.Xw oauthRedirectURI - mobilesdk://android/pn/tester + testsfdc:///mobilesdk/detect/oauth/done oauthScopes web From 08ea03e96f376b3fab4ba77edd59439ac69d8478 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Tue, 1 Oct 2024 16:28:31 -0600 Subject: [PATCH 10/10] @W-16171422: [iOS] Update Native Login Sample App to include QR Code Login Flow (Updates To Instructions For Enabling QR Code Log In) --- .../iOSNativeSwiftTemplate/AppDelegate.swift | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift index e9891710..29c939c4 100644 --- a/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift +++ b/iOSNativeSwiftTemplate/iOSNativeSwiftTemplate/AppDelegate.swift @@ -35,11 +35,8 @@ class AppDelegate : UIResponder, UIApplicationDelegate { super.init() MobileSyncSDKManager.initializeSDK() - // Uncomment when disabling log in via Salesforce UI Bridge API generated QR codes - //MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true - //UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { - // return LoginTypeSelectionViewController() - //} + // Uncomment when enabling log in via Salesforce UI Bridge API generated QR codes. + // self.setupQrCodeLogin() } // MARK: UISceneSession Lifecycle @@ -80,6 +77,13 @@ class AppDelegate : UIResponder, UIApplicationDelegate { } } + private func setupQrCodeLogin() { + MobileSyncSDKManager.shared.isQrCodeLoginEnabled = true + UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { + return LoginTypeSelectionViewController() + } + } + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { // Uncomment the code below to register your device token with the push notification manager // didRegisterForRemoteNotifications(deviceToken)