diff --git a/.claude/skills/update-ios-deployment-target/SKILL.md b/.claude/skills/update-ios-deployment-target/SKILL.md new file mode 100644 index 0000000000..f16896a2ab --- /dev/null +++ b/.claude/skills/update-ios-deployment-target/SKILL.md @@ -0,0 +1,156 @@ +# Update iOS Minimum Deployment Target + +This skill updates the minimum iOS deployment target across the entire Salesforce Mobile SDK for iOS repository. + +## When to Use +- When bumping the minimum supported iOS version for a new SDK release +- Typically done once per major release cycle + +## What This Skill Does + +Updates the iOS deployment target in all necessary locations: + +1. **CocoaPods Specifications** - Updates platform version in all 5 podspec files +2. **Build Configuration** - Updates Xcode configuration files +3. **Project Files** - Updates all .pbxproj files for libraries and sample apps +4. **Installation Scripts** - Updates version checks in install.sh +5. **Documentation** - Updates readme.md with new minimum version +6. **Helper Scripts** - Updates mobilesdk_pods.rb deployment target +7. **GitHub Actions Workflows** - Updates CI workflow matrices and runtime installation steps +8. **Code Cleanup** - Identifies and removes obsolete version checks in source code +9. **Comment Updates** - Updates version references in code comments + +## Usage + +When invoked, ask the user for: +- **Current minimum iOS version** (e.g., "16.0") +- **New minimum iOS version** (e.g., "17.0") +- **Corresponding minimum Xcode version** (e.g., "16.0" for iOS 17) + +## Step-by-Step Process + +### 1. Update CocoaPods Specifications +Update `s.platform = :ios, "X.0"` in: +- MobileSync.podspec +- SalesforceAnalytics.podspec +- SalesforceSDKCommon.podspec +- SalesforceSDKCore.podspec +- SmartStore.podspec + +### 2. Update Build Configuration +In `configuration/Packaging-Dynamic.xcconfig`: +- Change `IPHONEOS_DEPLOYMENT_TARGET = X.0` + +### 3. Update Helper Scripts +In `mobilesdk_pods.rb`: +- Update `change_deployment_target(target, 'X.0')` + +### 4. Update Installation Script +In `install.sh`: +- Update iOS version check strings (e.g., "iOS 15.0" → "iOS 17.0") +- Update Xcode version requirements (XCODE_MIN_VERSION and XCODE_MIN_VERSION_STR) + +### 5. Update Documentation +In `readme.md`: +- Update minimum iOS version requirement statement + +### 6. Update Xcode Project Files +Find all .pbxproj files and update `IPHONEOS_DEPLOYMENT_TARGET`: +- libs/MobileSync/MobileSync.xcodeproj/project.pbxproj +- libs/SalesforceAnalytics/SalesforceAnalytics.xcodeproj/project.pbxproj +- libs/SalesforceSDKCommon/SalesforceSDKCommon.xcodeproj/project.pbxproj +- libs/SalesforceSDKCore/SalesforceSDKCore.xcodeproj/project.pbxproj +- libs/SmartStore/SmartStore.xcodeproj/project.pbxproj +- Sample apps (MobileSyncExplorer, RestAPIExplorer, etc.) + +### 7. Update GitHub Actions Workflows +Remove the old minimum iOS version from CI workflows and clean up runtime installation steps: + +In `.github/workflows/nightly.yaml`: +- Remove old iOS version from test matrix (e.g., `ios: [^26, ^18, ^17]` → `ios: [^26, ^18]`) +- Remove old iOS version from build matrix +- Remove corresponding Xcode version mapping from matrix.include + +In `.github/workflows/ui-test-nightly.yaml`: +- Remove old iOS version from test matrix +- Remove corresponding Xcode version mapping from matrix.include + +### 8. Code Cleanup - Remove Obsolete Version Checks +Search for and review code with version-specific conditional compilation: +- `#if __IPHONE_OS_VERSION_MAX_ALLOWED >= [OLD_VERSION]` +- `@available(iOS X.Y, *)` +- `if #available(iOS X.Y, *)` + +For each occurrence where the check is for a version now below the new minimum: +- Remove the conditional wrapper +- Keep only the modern code path +- Remove else/fallback branches for old iOS versions + +Example patterns to search for: +```bash +# Find preprocessor conditionals +grep -r "#if __IPHONE_OS_VERSION_MAX_ALLOWED" libs/ + +# Find availability checks in Swift +grep -r "@available(iOS" libs/ + +# Find availability checks in Objective-C +grep -r "respondsToSelector" libs/ +``` + +### 9. Update Version References in Comments +Search for and update comments that reference the old minimum version: +```bash +grep -r "iOS [OLD_VERSION]" libs/ --include="*.swift" --include="*.m" --include="*.h" +``` + +## Post-Update Tasks + +1. **Build Verification**: Build all library schemes to verify no compilation errors +2. **Sample App Check**: Build and run sample apps (RestAPIExplorer, MobileSyncExplorer) + + +## Important Notes + +- **STOP and FLAG for human review**: This is a significant change that affects all SDK consumers +- **Release timing**: Only bump deployment target at major releases, never patches +- **Breaking change**: Document this in migration guide and release notes + + +## Example Command Flow + +```bash +# 1. Create a feature branch +git checkout -b bump-ios-18 + +# 2. Use this skill to make all updates +# (skill automates file edits) + +# 3. Search for version-specific code +grep -r "@available(iOS 17" libs/ --include="*.swift" +grep -r "#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 170000" libs/ + +# 4. Build all libraries +xcodebuild -workspace SalesforceMobileSDK.xcworkspace -scheme SalesforceSDKCore -sdk iphonesimulator +xcodebuild -workspace SalesforceMobileSDK.xcworkspace -scheme SmartStore -sdk iphonesimulator +xcodebuild -workspace SalesforceMobileSDK.xcworkspace -scheme MobileSync -sdk iphonesimulator + +``` + +## Historical References +- PR #3796: iOS 16 → iOS 17 bump +- PR #3681: iOS 15 → iOS 16 bump + +## Checklist + +Before marking complete: +- [ ] All 5 podspec files updated +- [ ] Packaging-Dynamic.xcconfig updated +- [ ] mobilesdk_pods.rb updated +- [ ] install.sh updated (both iOS and Xcode versions) +- [ ] readme.md updated +- [ ] All .pbxproj files updated (libraries + sample apps) +- [ ] Obsolete version checks removed from code +- [ ] Version references in comments updated +- [ ] All libraries build successfully +- [ ] Sample apps build diff --git a/.claude/skills/update-sqlcipher/SKILL.md b/.claude/skills/update-sqlcipher/SKILL.md new file mode 100644 index 0000000000..033bb83eae --- /dev/null +++ b/.claude/skills/update-sqlcipher/SKILL.md @@ -0,0 +1,269 @@ +--- +skill: sqlcipher-update +description: Update SQLCipher dependency in Salesforce Mobile SDK for iOS +globs: + - "*.podspec" + - "libs/SmartStore/**/*.swift" + - "libs/SmartStore/**/*.h" + - "libs/SmartStore/**/*.m" +tags: + - dependency-update + - sqlcipher + - encryption + - smartstore +--- + +# Update SQLCipher Skill + +This skill automates the process of updating the SQLCipher library version in the SalesforceMobileSDK-iOS project. + +## When to Use +Use this skill when you need to: +- Update SQLCipher to a newer version for security patches or new features +- Track changes in SQLCipher's OpenSSL provider version +- Handle API changes in new SQLCipher versions + +## Background +SQLCipher is an open-source extension to SQLite that provides transparent 256-bit AES encryption of database files. The SDK uses it in the SmartStore library for secure local data storage. + +## Parameters +- `NEW_VERSION`: The new SQLCipher version (e.g., "4.6.1", "4.6.2") +- `OLD_VERSION`: The current SQLCipher version (default: check podspecs) +- `NEW_PROVIDER_VERSION`: The cipher provider version bundled with the new SQLCipher (check SQLCipher release notes) + +## Prerequisite +Podspec for the new version is available on SalesforceMobileSDK-iOS-Specs + +## Process + +### 1. Research the New Version + +Before starting, check the SQLCipher release notes: +- Visit: https://github.com/sqlcipher/sqlcipher/releases +- Review changes, breaking changes, and new features +- Note the provider version included (important for tests) +- Check for API changes that might affect the SDK + +**Key things to look for:** +- Provider version changes (OpenSSL/LibTomCrypt versions) +- C API signature changes (sqlite3_*, sqlcipher_*) +- Deprecated PRAGMA statements or behavior changes +- Security fixes or enhancements +- Changes to encryption algorithms or key derivation + +### 2. Update Dependency Version + +Update SQLCipher version in the podspec file, SmartStore.xcodeproj and mobilesdk_pods.rb: + +**SmartStore.podspec** +```ruby +s.dependency 'SQLCipher', '~> OLD_VERSION' +``` + +Change to: +```ruby +s.dependency 'SQLCipher', '~> NEW_VERSION' +``` + +**Files to update:** +- `SmartStore.podspec` - SmartStore pod specification +- `SmartStore.xcodeproj` +- `mobilesdk_pods.rb` + +**Note:** The SDK supports exact version (`= 4.6.1`), minimum version (`>= 4.6.1`), or pessimistic version (`~> 4.6.1`) constraints depending on stability requirements. + +### 3. Update Version Tests + +Update libs/SmartStore/SmartStoreTests/SFSmartStoreTests.m: + +Update the SQLCipher version test: + +- (void) testSqlCipherVersion +{ + NSString* version = [self.store getSQLCipherVersion]; + XCTAssertEqualObjects(version, @"4.10.0 community"); +} + +Update the cipher provider version test: + +- (void) testCipherProviderVersion { + NSString *cipherProviderVersion = [self.store getCipherProviderVersion]; + XCTAssertNotNil(cipherProviderVersion); + XCTAssertTrue(cipherProviderVersion.length > 0, @"cipherProviderVersion should not be an empty string"); +} + +Note: The OpenSSL version format is typically like "OpenSSL 3.0.17 1 Jul 2025" and the LibTomCrypt format is like "1.18.2" - check the actual runtime value or SQLCipher release notes. + +Update the SQLLite version test: +- (void) testSqliteVersion { + NSString* version = [NSString stringWithUTF8String:sqlite3_libversion()]; + XCTAssertEqualObjects(version, @"3.50.4"); +} + +### 4. Check for API Changes + +Review if SQLCipher has any API changes that affect these files: + +**Key files to check:** +- `libs/SmartStore/SmartStore/Classes/SFSmartStore.h` - Main SmartStore interface +- `libs/SmartStore/SmartStore/Classes/SFSmartStore.m` - SmartStore implementation +- `libs/SmartStore/SmartStore/Classes/SFSoupIndex.h` - Indexing +- `libs/SmartStore/SmartStore/Classes/SFQuerySpec.h` - Query specifications +- `libs/SmartStore/SmartStore/Classes/Store/SFSmartStoreDatabaseManager.swift` - Database management +- `libs/SmartStore/SmartStore/Classes/Store/SFSmartStoreEncryption.swift` - Encryption handling + +**Historical API changes to watch for:** + +**SQLCipher 4.x series:** +- PRAGMA cipher_* statements may have new options +- sqlite3_key_v2() signature changes (rare) +- Changes to SQLITE_HEX encoding behavior +- JSON1 extension behavior modifications +- FTS5 full-text search changes + +**Common patterns:** +```objc +// Database opening with key +sqlite3_open() +sqlite3_key() // or sqlite3_key_v2() +PRAGMA cipher_page_size +PRAGMA kdf_iter +PRAGMA cipher_hmac_algorithm +PRAGMA cipher_kdf_algorithm +``` + +Check if any of these patterns need updates. + +### 5. Build SmartStore + +Build the SmartStore library to catch compilation issues: + +```bash +xcodebuild -workspace SalesforceMobileSDK.xcworkspace \ + -scheme SmartStore \ + -sdk iphonesimulator \ + build +``` + +Address any compilation errors related to: +- Deprecated SQLCipher APIs +- Changed function signatures (especially sqlite3_* functions) +- New required PRAGMA statements +- Header import changes (sqlite3.h, sqlcipher.h) +- Compiler warnings about encryption functions + +### 6. Run SmartStore Tests + +**CRITICAL**: Full SmartStore test suite must pass before proceeding. + +```bash +xcodebuild test -workspace SalesforceMobileSDK.xcworkspace \ + -scheme SmartStore \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 16' +``` + +**Key tests to verify:** +- Database open/close operations with encryption +- Key derivation and PRAGMA cipher settings +- CRUD operations (create, read, update, delete) +- Query performance and Smart SQL +- Index creation and queries +- JSON1 extension functionality +- Concurrent access patterns +- Data integrity after encryption/decryption +- Migration from databases created with older SQLCipher versions + +**Common test failures:** +- SQLITE_NOTADB errors (wrong encryption key/version) +- Query behavior changes (JOIN, JSON functions) +- Index performance differences +- PRAGMA statement compatibility issues + +If tests fail: +- Check SQLCipher release notes for behavior changes +- Review error logs for SQLCipher-specific errors +- Test with all SQLCipher editions if applicable (Community, Commercial, Enterprise, FIPS) +- Compare PRAGMA settings between versions + +### 7. Verify Other Libraries + +SmartStore is a dependency of MobileSync, so verify the change doesn't break downstream: + +```bash +# Build MobileSync +xcodebuild -workspace SalesforceMobileSDK.xcworkspace \ + -scheme MobileSync \ + -sdk iphonesimulator \ + build + +# Run MobileSync tests (they use SmartStore) +xcodebuild test -workspace SalesforceMobileSDK.xcworkspace \ + -scheme MobileSync \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 16' +``` + +MobileSync sync operations depend on SmartStore encryption working correctly. + +### 8. Create Pull Request + +When creating the PR: +- **Title:** "Moving to SQLCipher {NEW_VERSION}" or "Update SQLCipher to {NEW_VERSION}" +- **Description:** Include: + - SQLCipher version being updated to + - OpenSSL/LibTomCrypt version included + - Link to SQLCipher release notes + - Any API changes handled + - Test results summary + - Any breaking changes or migration notes + - Impact on SmartStore encryption features + +## File Checklist + +- [ ] `SmartStore.podspec` - Update SmartStore's SQLCipher dependency +- [ ] `SmartStore.xcodeproj` - Update the dependency for the workspace +- [ ] `mobilesdk_pods.rb` - Update the dependency for podfiles +- [ ] Version test files (if they exist) - Update expected versions +- [ ] SmartStore API implementation files - Check for API changes +- [ ] Run full SmartStore test suite +- [ ] Run full MobileSync test suite +- [ ] Verify on multiple iOS versions (min deployment target to latest) + +## Key Files Reference + +**Build Configuration:** +- `SmartStore.podspec` - SmartStore pod specification +- `SalesforceMobileSDK.xcworkspace` - Xcode workspace + +**Source Files (Objective-C):** +- `libs/SmartStore/SmartStore/Classes/SFSmartStore.h` - Main interface +- `libs/SmartStore/SmartStore/Classes/SFSmartStore.m` - Main implementation +- `libs/SmartStore/SmartStore/Classes/SFSoupIndex.h` - Indexing +- `libs/SmartStore/SmartStore/Classes/SFQuerySpec.h` - Queries + +**Source Files (Swift):** +- `libs/SmartStore/SmartStore/Classes/Store/SFSmartStoreDatabaseManager.swift` - Database management +- `libs/SmartStore/SmartStore/Classes/Store/SFSmartStoreEncryption.swift` - Encryption + +**Test Files:** +- `libs/SmartStore/SmartStoreTests/` - SmartStore test suite + + +## Notes + +- SQLCipher updates are usually straightforward but can have subtle issues +- Always test thoroughly on real devices, not just simulators +- Check SQLCipher's GitHub issues before and after updating +- The community edition (default) includes "community" in the version string +- Crypto provider version changes are common and must be verified in tests +- Test with encrypted databases from previous SDK versions to ensure migration works + +## Resources + +- SQLCipher: https://www.zetetic.net/sqlcipher/ +- SQLCipher iOS: https://github.com/sqlcipher/sqlcipher +- SQLCipher Releases: https://github.com/sqlcipher/sqlcipher/releases +- SQLCipher Documentation: https://www.zetetic.net/sqlcipher/documentation/ +- CocoaPods: https://cocoapods.org/ +- SmartStore docs: https://forcedotcom.github.io/SalesforceMobileSDK-iOS/Documentation/SmartStore/html/index.html diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 11ac989057..ddee20dc23 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -12,14 +12,12 @@ jobs: fail-fast: false matrix: lib: [SalesforceSDKCommon, SalesforceAnalytics, SalesforceSDKCore, SmartStore, MobileSync] - ios: [^26, ^18, ^17] + ios: [^26, ^18] include: - ios: ^26 xcode: ^26 - ios: ^18 xcode: ^16 - - ios: ^17 - xcode: ^16 uses: ./.github/workflows/reusable-test-workflow.yaml with: lib: ${{ matrix.lib }} @@ -32,14 +30,12 @@ jobs: fail-fast: false matrix: app: [RestAPIExplorer, MobileSyncExplorer, AuthFlowTester] - ios: [^26, ^18, ^17] + ios: [^26, ^18] include: - ios: ^26 xcode: ^26 - ios: ^18 xcode: ^16 - - ios: ^17 - xcode: ^16 uses: ./.github/workflows/reusable-build-workflow.yaml with: app: ${{ matrix.app }} diff --git a/.github/workflows/reusable-build-workflow.yaml b/.github/workflows/reusable-build-workflow.yaml index ec928f074f..4c97fa7462 100644 --- a/.github/workflows/reusable-build-workflow.yaml +++ b/.github/workflows/reusable-build-workflow.yaml @@ -34,9 +34,6 @@ jobs: ref: ${{ github.head_ref }} - name: Install Dependencies run: ./install.sh - - name: Install iOS 17 runtime if needed - if: ${{ inputs.ios == '^17' }} - run: xcodes runtimes install "iOS 17.5" - uses: mxcl/xcodebuild@v3 with: xcode: ${{ inputs.xcode }} diff --git a/.github/workflows/reusable-test-workflow.yaml b/.github/workflows/reusable-test-workflow.yaml index 7ffbd9d57c..3844c89738 100644 --- a/.github/workflows/reusable-test-workflow.yaml +++ b/.github/workflows/reusable-test-workflow.yaml @@ -38,9 +38,6 @@ jobs: run: | ./install.sh echo $TEST_CREDENTIALS > ./shared/test/test_credentials.json - - name: Install iOS 17 runtime if needed - if: ${{ inputs.ios == '^17' }} - run: xcodes runtimes install "iOS 17.5" - uses: mxcl/xcodebuild@v3 id: xcodebuild with: diff --git a/.github/workflows/reusable-ui-test-workflow.yaml b/.github/workflows/reusable-ui-test-workflow.yaml index ee242a80c0..03bd896ed3 100644 --- a/.github/workflows/reusable-ui-test-workflow.yaml +++ b/.github/workflows/reusable-ui-test-workflow.yaml @@ -69,9 +69,6 @@ jobs: run: | ./install.sh echo "$UI_TEST_CONFIG" > ./shared/test/ui_test_config.json - - name: Install iOS 17 runtime if needed - if: ${{ inputs.ios == '^17' }} - run: xcodes runtimes install "iOS 17.5" # Select Xcode only (mxcl action does not support -retry-tests-on-failure) - uses: mxcl/xcodebuild@v3 with: diff --git a/.github/workflows/ui-test-nightly.yaml b/.github/workflows/ui-test-nightly.yaml index ea3a60117a..b2afe6c602 100644 --- a/.github/workflows/ui-test-nightly.yaml +++ b/.github/workflows/ui-test-nightly.yaml @@ -10,14 +10,12 @@ jobs: strategy: fail-fast: false matrix: - ios: [^26, ^18, ^17] + ios: [^26, ^18] include: - ios: ^26 xcode: ^26 - ios: ^18 xcode: ^16 - - ios: ^17 - xcode: ^16 uses: ./.github/workflows/reusable-ui-test-workflow.yaml with: ios: ${{ matrix.ios }} diff --git a/CLAUDE.md b/CLAUDE.md index dafa184728..e697deb9e7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,7 +42,7 @@ MobileSync - [MobileSync](https://forcedotcom.github.io/SalesforceMobileSDK-iOS/Documentation/MobileSync/html/index.html) ### iOS Build Details -- **Minimum target**: iOS 17.0 +- **Minimum target**: iOS 18.0 - **Workspace**: `SalesforceMobileSDK.xcworkspace` (open this, not individual `.xcodeproj` files) - **Setup**: Run `./install.sh` after cloning to pull submodule dependencies - **Dependency management**: CocoaPods (podspecs at repo root) + Swift Package Manager diff --git a/MobileSync.podspec b/MobileSync.podspec index ae7b1c7bbc..a5004c4d3f 100644 --- a/MobileSync.podspec +++ b/MobileSync.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "MobileSync" - s.version = "13.2.0" + s.version = "14.0.0" s.summary = "Salesforce Mobile SDK for iOS - MobileSync" s.homepage = "https://github.com/forcedotcom/SalesforceMobileSDK-iOS" s.license = { :type => "Salesforce.com Mobile SDK License", :file => "LICENSE.md" } s.author = { "Kevin Hawkins" => "khawkins@salesforce.com" } - s.platforms = { :ios => "17.0", :visionos => "2.0" } + s.platforms = { :ios => "18.0", :visionos => "2.0" } s.swift_versions = ['5.0'] s.source = { :git => "https://github.com/forcedotcom/SalesforceMobileSDK-iOS.git", @@ -21,7 +21,7 @@ Pod::Spec.new do |s| mobilesync.dependency 'SmartStore', "~>#{s.version}" mobilesync.source_files = 'libs/MobileSync/MobileSync/Classes/**/*.{h,m,swift}', 'libs/MobileSync/MobileSync/MobileSync.h' - mobilesync.public_header_files = 'libs/MobileSync/MobileSync/Classes/Config/SFSDKSyncsConfig.h', 'libs/MobileSync/MobileSync/Classes/Instrumentation/SFMobileSyncSyncManager+Instrumentation.h', 'libs/MobileSync/MobileSync/Classes/Manager/MobileSyncSDKManager.h', 'libs/MobileSync/MobileSync/Classes/Manager/SFLayoutSyncManager.h', 'libs/MobileSync/MobileSync/Classes/Manager/SFMetadataSyncManager.h', 'libs/MobileSync/MobileSync/Classes/Manager/SFMobileSyncSyncManager.h', 'libs/MobileSync/MobileSync/Classes/Model/SFLayout.h', 'libs/MobileSync/MobileSync/Classes/Model/SFMetadata.h', 'libs/MobileSync/MobileSync/Classes/Model/SFMobileSyncPersistableObject.h', 'libs/MobileSync/MobileSync/Classes/Model/SFObject.h', 'libs/MobileSync/MobileSync/Classes/Target/SFAdvancedSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFBatchSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFLayoutSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFMetadataSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFMruSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFParentChildrenSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFParentChildrenSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFRefreshSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSoqlSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSoslSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSyncTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Util/SFChildrenInfo.h', 'libs/MobileSync/MobileSync/Classes/Util/SFMobileSyncConstants.h', 'libs/MobileSync/MobileSync/Classes/Util/SFMobileSyncNetworkUtils.h', 'libs/MobileSync/MobileSync/Classes/Util/SFMobileSyncObjectUtils.h', 'libs/MobileSync/MobileSync/Classes/Util/SFParentChildrenSyncHelper.h', 'libs/MobileSync/MobileSync/Classes/Util/SFParentInfo.h', 'libs/MobileSync/MobileSync/Classes/Util/SFSDKMobileSyncLogger.h', 'libs/MobileSync/MobileSync/Classes/Util/SFSyncOptions.h', 'libs/MobileSync/MobileSync/Classes/Util/SFSyncState.h', 'libs/MobileSync/MobileSync/MobileSync.h' + mobilesync.public_header_files = 'libs/MobileSync/MobileSync/Classes/Config/SFSDKSyncsConfig.h', 'libs/MobileSync/MobileSync/Classes/Manager/MobileSyncSDKManager.h', 'libs/MobileSync/MobileSync/Classes/Manager/SFLayoutSyncManager.h', 'libs/MobileSync/MobileSync/Classes/Manager/SFMetadataSyncManager.h', 'libs/MobileSync/MobileSync/Classes/Manager/SFMobileSyncSyncManager.h', 'libs/MobileSync/MobileSync/Classes/Model/SFLayout.h', 'libs/MobileSync/MobileSync/Classes/Model/SFMetadata.h', 'libs/MobileSync/MobileSync/Classes/Model/SFMobileSyncPersistableObject.h', 'libs/MobileSync/MobileSync/Classes/Model/SFObject.h', 'libs/MobileSync/MobileSync/Classes/Target/SFAdvancedSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFBatchSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFLayoutSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFMetadataSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFMruSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFParentChildrenSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFParentChildrenSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFRefreshSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSoqlSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSoslSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSyncDownTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSyncTarget.h', 'libs/MobileSync/MobileSync/Classes/Target/SFSyncUpTarget.h', 'libs/MobileSync/MobileSync/Classes/Util/SFChildrenInfo.h', 'libs/MobileSync/MobileSync/Classes/Util/SFMobileSyncConstants.h', 'libs/MobileSync/MobileSync/Classes/Util/SFMobileSyncNetworkUtils.h', 'libs/MobileSync/MobileSync/Classes/Util/SFMobileSyncObjectUtils.h', 'libs/MobileSync/MobileSync/Classes/Util/SFParentChildrenSyncHelper.h', 'libs/MobileSync/MobileSync/Classes/Util/SFParentInfo.h', 'libs/MobileSync/MobileSync/Classes/Util/SFSDKMobileSyncLogger.h', 'libs/MobileSync/MobileSync/Classes/Util/SFSyncOptions.h', 'libs/MobileSync/MobileSync/Classes/Util/SFSyncState.h', 'libs/MobileSync/MobileSync/MobileSync.h' mobilesync.prefix_header_contents = '#import "SFSDKMobileSyncLogger.h"' mobilesync.resource_bundles = { 'MobileSync' => [ 'libs/MobileSync/MobileSync/PrivacyInfo.xcprivacy' ] } mobilesync.requires_arc = true diff --git a/SalesforceAnalytics.podspec b/SalesforceAnalytics.podspec index b6098d26fa..85f3eac7e3 100644 --- a/SalesforceAnalytics.podspec +++ b/SalesforceAnalytics.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "SalesforceAnalytics" - s.version = "13.2.0" + s.version = "14.0.0" s.summary = "Salesforce Mobile SDK for iOS" s.homepage = "https://github.com/forcedotcom/SalesforceMobileSDK-iOS" s.license = { :type => "Salesforce.com Mobile SDK License", :file => "LICENSE.md" } s.author = { "Bharath Hariharan" => "bhariharan@salesforce.com" } - s.platforms = { :ios => "17.0", :visionos => "2.0" } + s.platforms = { :ios => "18.0", :visionos => "2.0" } s.source = { :git => "https://github.com/forcedotcom/SalesforceMobileSDK-iOS.git", :tag => "v#{s.version}" } diff --git a/SalesforceSDKCommon.podspec b/SalesforceSDKCommon.podspec index aac1b0f8aa..02b1676470 100644 --- a/SalesforceSDKCommon.podspec +++ b/SalesforceSDKCommon.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "SalesforceSDKCommon" - s.version = "13.2.0" + s.version = "14.0.0" s.summary = "Salesforce Mobile SDK for iOS" s.homepage = "https://github.com/forcedotcom/SalesforceMobileSDK-iOS" s.license = { :type => "Salesforce.com Mobile SDK License", :file => "LICENSE.md" } s.author = { "Raj Rao" => "rao.r@salesforce.com" } - s.platforms = { :ios => "17.0", :visionos => "2.0" } + s.platforms = { :ios => "18.0", :visionos => "2.0" } s.swift_versions = ['5.0'] s.source = { :git => "https://github.com/forcedotcom/SalesforceMobileSDK-iOS.git", @@ -19,7 +19,7 @@ Pod::Spec.new do |s| s.subspec 'SalesforceSDKCommon' do |sdkcommon| sdkcommon.source_files = 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/**/*.{h,m,swift}', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/SalesforceSDKCommon.h' - sdkcommon.public_header_files = 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Logger/SFDefaultLogger.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Logger/SFLogger.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/NSUserDefaults+SFAdditions.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFFileProtectionHelper.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFJsonUtils.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFPathUtil.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKDatasharingHelper.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKReachability.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKSafeMutableArray.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKSafeMutableDictionary.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKSafeMutableSet.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSwiftDetectUtil.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFTestContext.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/SalesforceSDKCommon.h' + sdkcommon.public_header_files = 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Logger/SFDefaultLogger.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Logger/SFLogger.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/NSUserDefaults+SFAdditions.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFFileProtectionHelper.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFJsonUtils.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFPathUtil.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKDatasharingHelper.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKReachability.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKSafeMutableArray.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKSafeMutableDictionary.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSDKSafeMutableSet.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFSwiftDetectUtil.h', 'libs/SalesforceSDKCommon/SalesforceSDKCommon/SalesforceSDKCommon.h' sdkcommon.prefix_header_contents = '' sdkcommon.resource_bundles = { 'SalesforceSDKCommon' => [ 'libs/SalesforceSDKCommon/SalesforceSDKCommon/PrivacyInfo.xcprivacy' ] } sdkcommon.requires_arc = true diff --git a/SalesforceSDKCore.podspec b/SalesforceSDKCore.podspec index 543420c963..2e368d539e 100644 --- a/SalesforceSDKCore.podspec +++ b/SalesforceSDKCore.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "SalesforceSDKCore" - s.version = "13.2.0" + s.version = "14.0.0" s.summary = "Salesforce Mobile SDK for iOS" s.homepage = "https://github.com/forcedotcom/SalesforceMobileSDK-iOS" s.license = { :type => "Salesforce.com Mobile SDK License", :file => "LICENSE.md" } s.author = { "Kevin Hawkins" => "khawkins@salesforce.com" } - s.platforms = { :ios => "17.0", :visionos => "2.0" } + s.platforms = { :ios => "18.0", :visionos => "2.0" } s.swift_versions = ['5.0'] s.source = { :git => "https://github.com/forcedotcom/SalesforceMobileSDK-iOS.git", @@ -25,7 +25,7 @@ Pod::Spec.new do |s| sdkcore.resources = ['shared/resources/SalesforceSDKAssets.xcassets'] sdkcore.source_files = 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/**/*.{h,m,swift}', 'libs/SalesforceSDKCore/SalesforceSDKCore/SalesforceSDKCore.h' # public_header_files is automatically populated by update_podspec_headers.sh which is run when building SalesforceSDKCore - sdkcore.public_header_files = 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKAILTNPublisher.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKAnalyticsPublisher.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKEventBuilderHelper.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKSalesforceAnalyticsManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSData+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSData+SFSDKUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSDictionary+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSString+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSURL+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSURLResponse+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SFFormatUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SFSDKAppConfig.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SFSDKAppFeatureMarkers.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIDevice+SFHardware.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIScreen+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKLoginFlowSelectionView.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUITableViewCell.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUserSelectionNavViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUserSelectionTableViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUserSelectionView.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Identity/SFIdentityCoordinator.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Identity/SFIdentityData.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFInstrumentation.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFMethodInterceptor.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFSDKInstrumentationHelper.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHost.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHostDelegate.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHostListViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHostStorage.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFSDKLoginViewControllerConfig.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthInfo.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthOrgAuthConfiguration.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthSessionRefresher.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/PushNotification/SFSDKPushNotificationDecryption.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/PushNotification/SFSDKPushNotificationError.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/PushNotification/SFSDKPushNotificationFieldsConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFNetwork.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+Blocks.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+Files.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+Notifications.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+QueryBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestRequest.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKBatchRequest.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKBatchResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKCollectionResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKCompositeRequest.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKCompositeResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKPrimingRecordsResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSObjectTree.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Security/SFSDKCryptoUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKAsyncProcessListener.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKTestCredentialsData.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKTestRequestListener.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFAuthErrorHandlerList.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccount.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountIdentity.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/ViewControllers/SFDefaultUserManagementDetailViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/ViewControllers/SFDefaultUserManagementListViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/ViewControllers/SFDefaultUserManagementViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/NSURL+SFStringUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFApplicationHelper.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFDirectoryManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFManagedPreferences.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFPreferences.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthConfigUtil.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKCoreLogger.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuthConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKResourceUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKSoqlBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKSoslBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKSoslReturningBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKViewControllerConfig.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKWebUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SalesforceSDKCoreDefines.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/UIColor+SFColors.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKAlertMessage.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKAlertMessageBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKNavigationController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKWindowContainer.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKWindowManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/SalesforceSDKCore.h' + sdkcore.public_header_files = 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKAILTNPublisher.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKAnalyticsPublisher.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKEventBuilderHelper.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Analytics/SFSDKSalesforceAnalyticsManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSData+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSData+SFSDKUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSDictionary+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSString+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSURL+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/NSURLResponse+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SFFormatUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SFSDKAppConfig.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SFSDKAppFeatureMarkers.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIDevice+SFHardware.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIScreen+SFAdditions.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKLoginFlowSelectionView.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUITableViewCell.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUserSelectionNavViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUserSelectionTableViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/IDP/SFSDKUserSelectionView.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Identity/SFIdentityCoordinator.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Identity/SFIdentityData.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHost.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHostDelegate.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHostListViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/LoginHost/SFSDKLoginHostStorage.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFSDKLoginViewControllerConfig.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthInfo.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthOrgAuthConfiguration.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthSessionRefresher.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/PushNotification/SFSDKPushNotificationDecryption.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/PushNotification/SFSDKPushNotificationError.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/PushNotification/SFSDKPushNotificationFieldsConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFNetwork.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+Blocks.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+Files.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+Notifications.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI+QueryBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestAPI.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFRestRequest.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKBatchRequest.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKBatchResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKCollectionResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKCompositeRequest.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKCompositeResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSDKPrimingRecordsResponse.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/RestAPI/SFSObjectTree.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Security/SFSDKCryptoUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKTestCredentialsData.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKTestRequestListener.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFAuthErrorHandlerList.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccount.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountIdentity.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/ViewControllers/SFDefaultUserManagementDetailViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/ViewControllers/SFDefaultUserManagementListViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/ViewControllers/SFDefaultUserManagementViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/NSURL+SFStringUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFApplicationHelper.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFDirectoryManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFManagedPreferences.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFPreferences.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthConfigUtil.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKCoreLogger.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuthConstants.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKResourceUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKSoqlBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKSoslBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKSoslReturningBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKViewControllerConfig.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKWebUtils.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SalesforceSDKCoreDefines.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/UIColor+SFColors.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKAlertMessage.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKAlertMessageBuilder.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKNavigationController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKViewController.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKWindowContainer.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Views/SFSDKWindowManager.h', 'libs/SalesforceSDKCore/SalesforceSDKCore/SalesforceSDKCore.h' sdkcore.requires_arc = true sdkcore.prefix_header_contents = '#import "SFSDKCoreLogger.h"', '#import "SalesforceSDKConstants.h"' diff --git a/SmartStore.podspec b/SmartStore.podspec index df9230a29c..098114d5a8 100644 --- a/SmartStore.podspec +++ b/SmartStore.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "SmartStore" - s.version = "13.2.0" + s.version = "14.0.0" s.summary = "Salesforce Mobile SDK for iOS - SmartStore" s.homepage = "https://github.com/forcedotcom/SalesforceMobileSDK-iOS" s.license = { :type => "Salesforce.com Mobile SDK License", :file => "LICENSE.md" } s.author = { "Kevin Hawkins" => "khawkins@salesforce.com" } - s.platforms = { :ios => "17.0", :visionos => "2.0" } + s.platforms = { :ios => "18.0", :visionos => "2.0" } s.swift_versions = ['5.0'] s.source = { :git => "https://github.com/forcedotcom/SalesforceMobileSDK-iOS.git", @@ -21,7 +21,7 @@ Pod::Spec.new do |s| smartstore.dependency 'SalesforceSDKCore', "~>#{s.version}" smartstore.dependency 'FMDB/SQLCipher', '~> 2.7.12' - smartstore.dependency 'SQLCipher', '~> 4.10.0' + smartstore.dependency 'SQLCipher', '~> 4.15.0' smartstore.source_files = 'libs/SmartStore/SmartStore/Classes/**/*.{h,m,swift}', 'libs/SmartStore/SmartStore/SmartStore.h' smartstore.public_header_files = 'libs/SmartStore/SmartStore/Classes/SFAlterSoupLongOperation.h', 'libs/SmartStore/SmartStore/Classes/SFQuerySpec.h', 'libs/SmartStore/SmartStore/Classes/SFSDKSmartStoreLogger.h', 'libs/SmartStore/SmartStore/Classes/SFSDKStoreConfig.h', 'libs/SmartStore/SmartStore/Classes/SFSmartSqlHelper.h', 'libs/SmartStore/SmartStore/Classes/SFSmartStore.h', 'libs/SmartStore/SmartStore/Classes/SFSmartStoreDatabaseManager.h', 'libs/SmartStore/SmartStore/Classes/SFSmartStoreInspectorViewController.h', 'libs/SmartStore/SmartStore/Classes/SFSmartStoreUtils.h', 'libs/SmartStore/SmartStore/Classes/SFSoupIndex.h', 'libs/SmartStore/SmartStore/Classes/SFStoreCursor.h', 'libs/SmartStore/SmartStore/Classes/SmartStoreSDKManager.h', 'libs/SmartStore/SmartStore/SmartStore.h' smartstore.prefix_header_contents = '#import "SFSDKSmartStoreLogger.h"', '#import ' diff --git a/configuration/Configuration-Debug.xcconfig b/configuration/Configuration-Debug.xcconfig index 7b8d6dd36e..1291d9ce70 100644 --- a/configuration/Configuration-Debug.xcconfig +++ b/configuration/Configuration-Debug.xcconfig @@ -10,5 +10,5 @@ ONLY_ACTIVE_ARCH = YES COPY_PHASE_STRIP = NO GCC_OPTIMIZATION_LEVEL = 0 -GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 SIGNPOST_ENABLED=1 $(inherited) +GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) MTL_ENABLE_DEBUG_INFO = YES diff --git a/configuration/Packaging-Dynamic.xcconfig b/configuration/Packaging-Dynamic.xcconfig index 8abe6ddd28..77c73eb3d3 100644 --- a/configuration/Packaging-Dynamic.xcconfig +++ b/configuration/Packaging-Dynamic.xcconfig @@ -6,4 +6,4 @@ // // -IPHONEOS_DEPLOYMENT_TARGET = 17.0 +IPHONEOS_DEPLOYMENT_TARGET = 18.0 diff --git a/configuration/Version.xcconfig b/configuration/Version.xcconfig index 56353b2e87..6ed64ce4c0 100644 --- a/configuration/Version.xcconfig +++ b/configuration/Version.xcconfig @@ -1 +1 @@ -CURRENT_PROJECT_VERSION = 13.2.0 +CURRENT_PROJECT_VERSION = 14.0.0 diff --git a/install.sh b/install.sh index c224af70ec..c78e3319cb 100755 --- a/install.sh +++ b/install.sh @@ -10,8 +10,8 @@ cd "$(dirname "$0")" # Check for iOS SDK minimum version -IOS_MIN_VERSION_NUM=170 -IOS_MIN_VERSION_STR="iOS 17.0" +IOS_MIN_VERSION_NUM=180 +IOS_MIN_VERSION_STR="iOS 18.0" ios_ver=`xcodebuild -version -sdk iphoneos | grep SDKVersion:` if [[ "$ios_ver" == "" ]] then diff --git a/libs/MobileSync/MobileSync.xcodeproj/project.pbxproj b/libs/MobileSync/MobileSync.xcodeproj/project.pbxproj index 712e78d37c..272bb1975a 100644 --- a/libs/MobileSync/MobileSync.xcodeproj/project.pbxproj +++ b/libs/MobileSync/MobileSync.xcodeproj/project.pbxproj @@ -127,8 +127,6 @@ CE1F0B0C19ACF95B0007F22F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1F0B0219ACF95B0007F22F /* SystemConfiguration.framework */; }; CE1F0B0D19ACF95B0007F22F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE1F0B0319ACF95B0007F22F /* UIKit.framework */; }; CE1F0B1919ACFD260007F22F /* test_credentials.json in Resources */ = {isa = PBXBuildFile; fileRef = CE1F0B1819ACFD260007F22F /* test_credentials.json */; }; - CE2BCCF4224A86C100C98308 /* SFMobileSyncSyncManager+Instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = CE2BCCF2224A86C000C98308 /* SFMobileSyncSyncManager+Instrumentation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CE2BCCF5224A86C100C98308 /* SFMobileSyncSyncManager+Instrumentation.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2BCCF3224A86C000C98308 /* SFMobileSyncSyncManager+Instrumentation.m */; }; CE4CE4221C0E5A35009F6029 /* SFMobileSyncSyncManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F22155A19DF4BAD00FF2D26 /* SFMobileSyncSyncManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE4CE4231C0E5A35009F6029 /* SFMobileSyncSyncManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F22155B19DF4BAD00FF2D26 /* SFMobileSyncSyncManager.m */; }; CE4CE4281C0E5A49009F6029 /* SFObject+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = CEF50A7B196B3EB60076264C /* SFObject+Internal.h */; }; @@ -436,8 +434,6 @@ CE1F0B0219ACF95B0007F22F /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; CE1F0B0319ACF95B0007F22F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; CE1F0B1819ACFD260007F22F /* test_credentials.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = test_credentials.json; path = ../../../shared/test/test_credentials.json; sourceTree = ""; }; - CE2BCCF2224A86C000C98308 /* SFMobileSyncSyncManager+Instrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SFMobileSyncSyncManager+Instrumentation.h"; path = "Instrumentation/SFMobileSyncSyncManager+Instrumentation.h"; sourceTree = ""; }; - CE2BCCF3224A86C000C98308 /* SFMobileSyncSyncManager+Instrumentation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SFMobileSyncSyncManager+Instrumentation.m"; path = "Instrumentation/SFMobileSyncSyncManager+Instrumentation.m"; sourceTree = ""; }; CE4CE2C91C0E463C009F6029 /* MobileSync.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MobileSync.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE617397196F469A00C63BDE /* SFMobileSyncConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFMobileSyncConstants.h; sourceTree = ""; }; CE617398196F469A00C63BDE /* SFMobileSyncConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFMobileSyncConstants.m; sourceTree = ""; }; @@ -652,8 +648,6 @@ CE2BCCF1224A86AF00C98308 /* Instrumentation */ = { isa = PBXGroup; children = ( - CE2BCCF2224A86C000C98308 /* SFMobileSyncSyncManager+Instrumentation.h */, - CE2BCCF3224A86C000C98308 /* SFMobileSyncSyncManager+Instrumentation.m */, ); name = Instrumentation; sourceTree = ""; @@ -876,7 +870,6 @@ CE4CE4381C0E5A75009F6029 /* SFMobileSyncNetworkUtils.h in Headers */, 4F307E331EBD49250040CFC4 /* SFParentChildrenSyncHelper.h in Headers */, 4FAA9B6222545FE00006810D /* SFSyncDownTask.h in Headers */, - CE2BCCF4224A86C100C98308 /* SFMobileSyncSyncManager+Instrumentation.h in Headers */, 4FCA4A981FBE4E0A00F081B3 /* SFSDKSyncsConfig.h in Headers */, CE4CE4311C0E5A49009F6029 /* SFMobileSyncPersistableObject+Internal.h in Headers */, 4FDCBD561E8DDC5C008F8FCE /* SFSyncTarget.h in Headers */, @@ -1269,7 +1262,6 @@ 6927E23F283C3E1400A16668 /* SyncTarget.swift in Sources */, 4F307E2A1EBA92450040CFC4 /* SFParentInfo.m in Sources */, 4FDCBD571E8DDC5C008F8FCE /* SFSyncDownTarget.m in Sources */, - CE2BCCF5224A86C100C98308 /* SFMobileSyncSyncManager+Instrumentation.m in Sources */, 4FCDFF7528402D510045CD29 /* CollectionSyncUpTarget.swift in Sources */, 4FAA9B6E225461910006810D /* SFCleanSyncGhostsTask.m in Sources */, FDCEC3CBF6FA262ACF305285 /* MobileSyncSDKManager.m in Sources */, @@ -1537,7 +1529,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; XROS_DEPLOYMENT_TARGET = 2.0; @@ -1584,7 +1576,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; diff --git a/libs/MobileSync/MobileSync/Classes/Instrumentation/SFMobileSyncSyncManager+Instrumentation.h b/libs/MobileSync/MobileSync/Classes/Instrumentation/SFMobileSyncSyncManager+Instrumentation.h deleted file mode 100644 index 19ed17351f..0000000000 --- a/libs/MobileSync/MobileSync/Classes/Instrumentation/SFMobileSyncSyncManager+Instrumentation.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - SFMobileSyncSyncManager+Instrumentation.h - SalesforceSDKCore - Created by Raj Rao on 3/21/19. - - Copyright (c) 2019-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 - -NS_ASSUME_NONNULL_BEGIN - -/// @deprecated Signpost logging is deprecated and this category will be removed in version 14.0. -SFSDK_DEPRECATED(13.2, 14.0, "Signpost logging is deprecated and will be removed."); -@interface SFMobileSyncSyncManager (Instrumentation) - -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/MobileSync/MobileSync/Classes/Instrumentation/SFMobileSyncSyncManager+Instrumentation.m b/libs/MobileSync/MobileSync/Classes/Instrumentation/SFMobileSyncSyncManager+Instrumentation.m deleted file mode 100644 index 33ba69cb03..0000000000 --- a/libs/MobileSync/MobileSync/Classes/Instrumentation/SFMobileSyncSyncManager+Instrumentation.m +++ /dev/null @@ -1,351 +0,0 @@ -/* - SFMobileSyncSyncManager+Instrumentation.m - SalesforceSDKCore - Created by Raj Rao on 3/21/19. - - Copyright (c) 2019-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 "SFMobileSyncSyncManager+Instrumentation.h" -#import -#import -#import -#import - -@implementation SFMobileSyncSyncManager (Instrumentation) - -+ (os_log_t)oslog { - static os_log_t _logger; - static dispatch_once_t pred; - dispatch_once(&pred, ^{ - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - _logger = os_log_create([appName cStringUsingEncoding:NSUTF8StringEncoding], [@"SFMobileSync" cStringUsingEncoding:NSUTF8StringEncoding]); - }); - return _logger; -} - - -+ (void)load{ - if ([SFSDKInstrumentationHelper isEnabled] && (self == SFMobileSyncSyncManager.self)) { - [self enableInstrumentation]; - } -} - -+ (void)enableInstrumentation { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - Class class = [self class]; - - SEL originalSelector = @selector(getSyncStatus:); - SEL swizzledSelector = @selector(instr_getSyncStatus:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(getSyncStatusByName:); - swizzledSelector = @selector(instr_getSyncStatusByName:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(hasSyncWithName:); - swizzledSelector = @selector(instr_hasSyncWithName:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(deleteSyncById:); - swizzledSelector = @selector(instr_deleteSyncById:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(deleteSyncByName:); - swizzledSelector = @selector(instr_deleteSyncByName:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(createSyncDown:options:soupName:syncName:); - swizzledSelector = @selector(instr_createSyncDown:options:soupName:syncName:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(syncDownWithTarget:soupName:updateBlock:); - swizzledSelector = @selector(instr_syncDownWithTarget:soupName:updateBlock:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(syncDownWithTarget:options:soupName:syncName:updateBlock:error:); - swizzledSelector = @selector(instr_syncDownWithTarget:options:soupName:syncName:updateBlock:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(reSync:updateBlock:error:); - swizzledSelector = @selector(instr_reSync:updateBlock:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(reSyncByName:updateBlock:error:); - swizzledSelector = @selector(instr_reSyncByName:updateBlock:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(createSyncUp:options:soupName:syncName:); - swizzledSelector = @selector(instr_createSyncUp:options:soupName:syncName:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(createSyncDown:options:soupName:syncName:); - swizzledSelector = @selector(instr_createSyncDown:options:soupName:syncName:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(syncUpWithOptions:soupName:updateBlock:); - swizzledSelector = @selector(instr_syncUpWithOptions:soupName:updateBlock:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(syncUpWithTarget:options:soupName:updateBlock:); - swizzledSelector = @selector(instr_syncUpWithTarget:options:soupName:updateBlock:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(syncUpWithTarget:options:soupName:syncName:updateBlock:error:); - swizzledSelector = @selector(instr_syncUpWithTarget:options:soupName:syncName:updateBlock:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(cleanResyncGhosts:completionStatusBlock:error:); - swizzledSelector = @selector(instr_cleanResyncGhosts:completionStatusBlock:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - }); -} - -- (SFSyncState*)instr_getSyncStatus:(NSNumber*)syncId { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "getSyncStatus", "storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - SFSyncState *result = [self instr_getSyncStatus:syncId]; - sf_os_signpost_interval_end(logger, sid, "getSyncStatus", "storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - return result; -} - -- (SFSyncState*)instr_getSyncStatusByName:(NSString*)syncName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "getSyncStatusByName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - SFSyncState *result = [self instr_getSyncStatusByName:syncName]; - sf_os_signpost_interval_end(logger, sid, "getSyncStatusByName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - return result; -} - -- (BOOL)instr_hasSyncWithName:(NSString*)syncName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "hasSyncWithName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - BOOL result = [self instr_hasSyncWithName:syncName]; - sf_os_signpost_interval_end(logger, sid, "hasSyncWithName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - return result; -} - -- (void)instr_deleteSyncById:(NSNumber*)syncId { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "deleteSyncById", "storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - [self instr_deleteSyncById:syncId]; - sf_os_signpost_interval_end(logger, sid, "deleteSyncById", "storeName:%{public}@ syncId:%@", self.store.storeName, syncId); -} - -- (void)instr_deleteSyncByName:(NSString*)syncName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "deleteSyncByName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - [self instr_deleteSyncByName:syncName]; - sf_os_signpost_interval_end(logger, sid, "deleteSyncByName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); -} - -- (SFSyncState *)instr_createSyncDown:(SFSyncDownTarget *)target options:(SFSyncOptions *)options soupName:(NSString *)soupName syncName:(NSString *)syncName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "deleteSyncByName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - SFSyncState *result = [self instr_createSyncDown:target options:options soupName:soupName syncName:syncName]; - sf_os_signpost_interval_end(logger, sid, "deleteSyncByName", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - return result; -} - -- (SFSyncState*)instr_syncDownWithTarget:(SFSyncDownTarget*)target soupName:(NSString*)soupName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "syncDownWithTarget:soupName:updateBlock", "storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - - SFSyncState *result = [self instr_syncDownWithTarget:target soupName:soupName updateBlock:^(SFSyncState * _Nonnull sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "syncDownWithTarget:soupName:updateBlock", "success storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "syncDownWithTarget:soupName:updateBlock", "failed storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } - if (updateBlock) { - updateBlock(sync); - } - }]; - return result; -} - -- (SFSyncState*)instr_syncDownWithTarget:(SFSyncDownTarget*)target options:(SFSyncOptions*)options soupName:(NSString*)soupName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "syncDownWithTarget:options:soupName:soupName:updateBlock", "storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - SFSyncState *result = [self instr_syncDownWithTarget:target options:options soupName:soupName updateBlock:^(SFSyncState *sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "syncDownWithTarget:options:soupName:soupName:updateBlock", "success storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "syncDownWithTarget:options:soupName:soupName:updateBlock", "failed storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } - if (updateBlock) { - updateBlock(sync); - } - } error:error]; - return result; -} - -- (SFSyncState*)instr_syncDownWithTarget:(SFSyncDownTarget*)target options:(SFSyncOptions*)options soupName:(NSString*)soupName syncName:(NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "syncDownWithTarget:options:soupName:soupName:syncName:updateBlock", "storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - SFSyncState *result = [self instr_syncDownWithTarget:target options:options soupName:soupName syncName:syncName updateBlock:^(SFSyncState *sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "syncDownWithTarget:options:soupName:syncName:updateBlock", "success storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "syncDownWithTarget:options:soupName:syncName:updateBlock", "failed storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } - if (updateBlock) { - updateBlock(sync); - } - } error:error]; - return result; -} - -- (SFSyncState*)instr_reSync:(NSNumber*)syncId updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "reSync:updateBlock", "storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - SFSyncState *result = [self instr_reSync:syncId updateBlock:^(SFSyncState *sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "reSync:updateBlock", "success storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "reSync:updateBlock", "failed storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - } - if (updateBlock) { - updateBlock(sync); - } - } error:error]; - return result; -} - -- (SFSyncState*)instr_reSyncByName:(NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "reSyncByName:updateBlock", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - SFSyncState *result = [self instr_reSyncByName:syncName updateBlock:^(SFSyncState *sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "reSyncByName:updateBlock", "success storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "reSyncByName:updateBlock", "failed storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - } - if (updateBlock) { - updateBlock(sync); - } - } error:error]; - return result; -} - -- (SFSyncState *)instr_createSyncUp:(SFSyncUpTarget *)target options:(SFSyncOptions *)options soupName:(NSString *)soupName syncName:(NSString *)syncName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "createSyncUp:options:soupName:syncName:updateBlock", "storeName:%{public}@ syncName:%{public}@", self.store.storeName, syncName); - SFSyncState *result = [self instr_createSyncUp:target options:options soupName:soupName syncName:syncName]; - sf_os_signpost_interval_end(logger, sid, "createSyncUp:options:soupName:syncName:updateBlock", "success storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - return result; -} - -- (SFSyncState*)instr_syncUpWithOptions:(SFSyncOptions*)options soupName:(NSString*)soupName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "syncUpWithOptions:soupName:updateBlock", "storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - SFSyncState *result = [self instr_syncUpWithOptions:options soupName:soupName updateBlock:^(SFSyncState *sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "syncUpWithOptions:soupName:updateBlock", "success storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "syncUpWithOptions:soupName:updateBlock", "failed storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } - if (updateBlock) { - updateBlock(sync); - } - }]; - return result; -} - -- (SFSyncState*)instr_syncUpWithTarget:(SFSyncUpTarget*)target options:(SFSyncOptions*)options - soupName:(NSString*)soupName - updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "syncUpWithTarget:options:soupName:updateBlock", "storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - SFSyncState *result = [self instr_syncUpWithTarget:target options:options soupName:soupName updateBlock:^(SFSyncState *sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "syncUpWithTarget:options:soupName:updateBlock", "success storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "syncUpWithTarget:options:soupName:updateBlock", "failed storeName:%{public}@ soupName:%{public}@", self.store.storeName, soupName); - } - if (updateBlock) { - updateBlock(sync); - } - }]; - return result; - -} - -- (SFSyncState*)instr_syncUpWithTarget:(SFSyncUpTarget*)target - options:(SFSyncOptions*)options - soupName:(NSString*)soupName - syncName:(NSString*)syncName - updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock - error:(NSError**)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "syncUpWithTarget:options:soupName:syncName:updateBlock", "storeName:%{public}@ soupName:%{public}@ syncName:%{public}@", self.store.storeName, soupName,syncName); - SFSyncState *result = [self instr_syncUpWithTarget:target options:options soupName:soupName syncName:syncName updateBlock:^(SFSyncState *sync) { - if ([sync isDone]) { - sf_os_signpost_interval_end(logger, sid, "syncUpWithTarget:options:soupName:syncName:updateBlock", "success storeName:%{public}@ soupName:%{public}@ syncName:%{public}@", self.store.storeName, soupName, syncName); - } else if ([sync hasFailed]) { - sf_os_signpost_interval_end(logger, sid, "syncUpWithTarget:options:soupName:syncName:updateBlock", "failed storeName:%{public}@ soupName:%{public}@ syncName:%{public}@", self.store.storeName, soupName, syncName); - } - if (updateBlock) { - updateBlock(sync); - } - } error:error]; - return result; -} - -- (BOOL)instr_cleanResyncGhosts:(NSNumber*)syncId completionStatusBlock:(SFSyncSyncManagerCompletionStatusBlock)completionStatusBlock - error:(NSError**)error { - - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "cleanResyncGhosts:completionStatusBlock", "storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - BOOL result = [self instr_cleanResyncGhosts:syncId completionStatusBlock:^(SFSyncStateStatus syncStatus, NSUInteger numRecords) { - if (syncStatus==SFSyncStateStatusDone) { - sf_os_signpost_interval_end(logger, sid, "cleanResyncGhosts:completionStatusBlock", "success storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - } else if (syncStatus==SFSyncStateStatusFailed) { - sf_os_signpost_interval_end(logger, sid, "cleanResyncGhosts:completionStatusBlock", "failed storeName:%{public}@ syncId:%@", self.store.storeName, syncId); - } - if (completionStatusBlock) { - completionStatusBlock(syncStatus,numRecords); - } - } error:error]; - return result; -} - -@end diff --git a/libs/MobileSync/MobileSync/MobileSync.h b/libs/MobileSync/MobileSync/MobileSync.h index f476bdb07c..313fdeb847 100644 --- a/libs/MobileSync/MobileSync/MobileSync.h +++ b/libs/MobileSync/MobileSync/MobileSync.h @@ -39,7 +39,6 @@ #import #import #import -#import #import #import #import diff --git a/libs/SalesforceAnalytics/SalesforceAnalytics.xcodeproj/project.pbxproj b/libs/SalesforceAnalytics/SalesforceAnalytics.xcodeproj/project.pbxproj index 6cbb114541..5fda0d8052 100644 --- a/libs/SalesforceAnalytics/SalesforceAnalytics.xcodeproj/project.pbxproj +++ b/libs/SalesforceAnalytics/SalesforceAnalytics.xcodeproj/project.pbxproj @@ -731,7 +731,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -790,7 +790,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 1; diff --git a/libs/SalesforceSDKCommon/SalesforceSDKCommon.xcodeproj/project.pbxproj b/libs/SalesforceSDKCommon/SalesforceSDKCommon.xcodeproj/project.pbxproj index f01645c361..de5690d7e3 100644 --- a/libs/SalesforceSDKCommon/SalesforceSDKCommon.xcodeproj/project.pbxproj +++ b/libs/SalesforceSDKCommon/SalesforceSDKCommon.xcodeproj/project.pbxproj @@ -38,8 +38,6 @@ B77F5D152170FFEE004F3005 /* SFFileProtectionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B77F5D102170FFED004F3005 /* SFFileProtectionHelper.m */; }; B77F5D172170FFEE004F3005 /* SFPathUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B77F5D112170FFED004F3005 /* SFPathUtil.m */; }; B77F5D192170FFEE004F3005 /* SFFileProtectionHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = B77F5D122170FFEE004F3005 /* SFFileProtectionHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B77F5D1F2171021F004F3005 /* SFTestContext.m in Sources */ = {isa = PBXBuildFile; fileRef = B77F5D1B2171021E004F3005 /* SFTestContext.m */; }; - B77F5D212171021F004F3005 /* SFTestContext.h in Headers */ = {isa = PBXBuildFile; fileRef = B77F5D1C2171021E004F3005 /* SFTestContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; B77F5D232171021F004F3005 /* SFSwiftDetectUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B77F5D1D2171021F004F3005 /* SFSwiftDetectUtil.m */; }; B77F5D252171021F004F3005 /* SFSwiftDetectUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = B77F5D1E2171021F004F3005 /* SFSwiftDetectUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; B78898BC218D0329006E0C77 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B78898BB218D0329006E0C77 /* Foundation.framework */; }; @@ -107,8 +105,6 @@ B77F5D102170FFED004F3005 /* SFFileProtectionHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFFileProtectionHelper.m; sourceTree = ""; }; B77F5D112170FFED004F3005 /* SFPathUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFPathUtil.m; sourceTree = ""; }; B77F5D122170FFEE004F3005 /* SFFileProtectionHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFFileProtectionHelper.h; sourceTree = ""; }; - B77F5D1B2171021E004F3005 /* SFTestContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFTestContext.m; sourceTree = ""; }; - B77F5D1C2171021E004F3005 /* SFTestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFTestContext.h; sourceTree = ""; }; B77F5D1D2171021F004F3005 /* SFSwiftDetectUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSwiftDetectUtil.m; sourceTree = ""; }; B77F5D1E2171021F004F3005 /* SFSwiftDetectUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSwiftDetectUtil.h; sourceTree = ""; }; B78898BB218D0329006E0C77 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -236,8 +232,6 @@ 4F5DDEB421A4B2520024E7F3 /* SFJsonUtils.m */, B77F5D1E2171021F004F3005 /* SFSwiftDetectUtil.h */, B77F5D1D2171021F004F3005 /* SFSwiftDetectUtil.m */, - B77F5D1C2171021E004F3005 /* SFTestContext.h */, - B77F5D1B2171021E004F3005 /* SFTestContext.m */, B77F5D122170FFEE004F3005 /* SFFileProtectionHelper.h */, B77F5D102170FFED004F3005 /* SFFileProtectionHelper.m */, B77F5D0F2170FFED004F3005 /* SFPathUtil.h */, @@ -316,7 +310,6 @@ B7136D31216686EB00F6A221 /* SFSDKReachability.h in Headers */, B7136D34216686EB00F6A221 /* SFSDKDatasharingHelper.h in Headers */, B77F5CF22170FF74004F3005 /* SFSDKSafeMutableDictionary.h in Headers */, - B77F5D212171021F004F3005 /* SFTestContext.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -505,7 +498,6 @@ B7136D5821669F7C00F6A221 /* SFDefaultLogger.m in Sources */, B7136D32216686EB00F6A221 /* NSUserDefaults+SFAdditions.m in Sources */, B77F5D172170FFEE004F3005 /* SFPathUtil.m in Sources */, - B77F5D1F2171021F004F3005 /* SFTestContext.m in Sources */, B77F5CF82170FF74004F3005 /* SFSDKSafeMutableArray.m in Sources */, B77B6CA4260D261C0074BA3C /* KeychainHelper.swift in Sources */, F2F4222528B6CBF40010EF0F /* KeychainItemManager.swift in Sources */, @@ -609,7 +601,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -669,7 +661,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFTestContext.h b/libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFTestContext.h deleted file mode 100644 index f9b601388d..0000000000 --- a/libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFTestContext.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Copyright (c) 2015-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. - */ - -// This class is intended to be used to set the application in testing context or -// live context. It could be used by application to implement mock logic under -// testing context so that application can be run without live connection - -#import - -NS_ASSUME_NONNULL_BEGIN - -/**Helps determine whether we're currently running tests or not. - */ -__attribute__((deprecated("Deprecated in Salesforce Mobile SDK 13.2 and will be removed in Salesforce Mobile SDK 14.0."))); -@interface SFTestContext : NSObject { - -} -/**Return YES if is running test - */ -+ (BOOL)isRunningTests; - -/**Update SFTestContext to indicate whether it is in testing context or live context - @param runningTests Yes if code is running under testing context - */ -+ (void)setIsRunningTests:(BOOL)runningTests; - -/** Sets an arbitrary object into the test context - @param object The object or nil to remove the object - @param key The key - */ -+ (void)setObject:(nullable id)object forKey:(id)key; - -/** Returns an arbitrary object from the test context - @param key The key - @return The object - */ -+ (id)objectForKey:(id)key; - -/** Removes all the stored objects - */ -+ (void)clearObjects; - -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFTestContext.m b/libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFTestContext.m deleted file mode 100644 index 6248f279a2..0000000000 --- a/libs/SalesforceSDKCommon/SalesforceSDKCommon/Classes/Util/SFTestContext.m +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright (c) 2015-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 "SFTestContext.h" - -static BOOL runningTests = NO; -static NSMutableDictionary *objects = nil; - -@implementation SFTestContext - -+ (void)initialize { - if (self == [SFTestContext class]) { - objects = [[NSMutableDictionary alloc] init]; - } -} - -+ (BOOL)isRunningTests { - return runningTests; -} - -+ (void)setIsRunningTests:(BOOL)newRunningTests { - runningTests = newRunningTests; -} - -+ (void)setObject:(id)object forKey:(id)key { - if (object) { - objects[key] = object; - } else { - [objects removeObjectForKey:key]; - } -} - -+ (id)objectForKey:(id)key { - return objects[key]; -} - -+ (void)clearObjects { - [objects removeAllObjects]; -} - -@end diff --git a/libs/SalesforceSDKCommon/SalesforceSDKCommon/SalesforceSDKCommon.h b/libs/SalesforceSDKCommon/SalesforceSDKCommon/SalesforceSDKCommon.h index 7a7f80b97a..ca0baca1a1 100644 --- a/libs/SalesforceSDKCommon/SalesforceSDKCommon/SalesforceSDKCommon.h +++ b/libs/SalesforceSDKCommon/SalesforceSDKCommon/SalesforceSDKCommon.h @@ -28,7 +28,6 @@ */ #import -#import #import #import #import diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore.xcodeproj/project.pbxproj b/libs/SalesforceSDKCore/SalesforceSDKCore.xcodeproj/project.pbxproj index bba012f897..565f941f96 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore.xcodeproj/project.pbxproj +++ b/libs/SalesforceSDKCore/SalesforceSDKCore.xcodeproj/project.pbxproj @@ -79,6 +79,7 @@ 4F3139682331C5C7007B3705 /* SFSDKAuthRootController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F3139672331C5B9007B3705 /* SFSDKAuthRootController.h */; }; 4F3ECD8A2EBBD150005020A6 /* SFOAuthCoordinatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F3ECD892EBBD150005020A6 /* SFOAuthCoordinatorTests.m */; }; 4F3ECD8C2EBBD182005020A6 /* SFOAuthInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F3ECD8B2EBBD182005020A6 /* SFOAuthInfoTests.m */; }; + 4FA1B2C32F0E000000000001 /* LoginForAdminTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA1B2C32F0E000000000002 /* LoginForAdminTests.swift */; }; 4F5727E327F27F1A0008CDA4 /* SFSDKPrimingRecordsResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F5727DC27F27F1A0008CDA4 /* SFSDKPrimingRecordsResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4F5727E427F27F1A0008CDA4 /* SFSDKPrimingRecordsResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F5727E227F27F1A0008CDA4 /* SFSDKPrimingRecordsResponse.m */; }; 4F5A49502E98711600C89DDD /* ScopeParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5A494F2E98711600C89DDD /* ScopeParser.swift */; }; @@ -97,8 +98,8 @@ 4F9E05342DD7BE1500548985 /* SFOAuthCredentialsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F9E05332DD7BE0A00548985 /* SFOAuthCredentialsTests.m */; }; 4FAUTHFLOW001234567890ABC /* AuthFlowTypesViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FAUTHFLOW112345678901ABC /* AuthFlowTypesViewTests.swift */; }; 4FBOOTCP001234567890ABCD /* LoginOptionsViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FBOOTCP112345678901ABCD /* LoginOptionsViewControllerTests.swift */; }; - 4FDISCOV001234567890ABCD /* DiscoveryResultEditorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FDISCOV112345678901ABCD /* DiscoveryResultEditorTests.swift */; }; 4FDEVINFO001234567890ABCD /* DevInfoViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FDEVINFO112345678901ABCD /* DevInfoViewControllerTests.swift */; }; + 4FDISCOV001234567890ABCD /* DiscoveryResultEditorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FDISCOV112345678901ABCD /* DiscoveryResultEditorTests.swift */; }; 4FE006B12EBEB65900CFD66F /* AuthFlowTypesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE006B02EBEB65900CFD66F /* AuthFlowTypesView.swift */; }; 4FE006B22EBEB65900CFD66F /* BootConfigEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE006AE2EBEB65900CFD66F /* BootConfigEditor.swift */; }; 4FE006B32EBEB65900CFD66F /* LoginOptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE006AF2EBEB65900CFD66F /* LoginOptionsViewController.swift */; }; @@ -212,13 +213,8 @@ B759CD8B1F8C10DC0081AA87 /* SFSDKErrorManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B759CD8A1F8C10DC0081AA87 /* SFSDKErrorManagerTests.m */; }; B767369120A4AB0200F04103 /* SFSDKNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = B767368F20A4AB0200F04103 /* SFSDKNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; B767369320A4AB0200F04103 /* SFSDKNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = B767369020A4AB0200F04103 /* SFSDKNavigationController.m */; }; - B767704D223AE5E400545C90 /* SFRestAPI+Instrumentation.m in Sources */ = {isa = PBXBuildFile; fileRef = B7677043223AE5E400545C90 /* SFRestAPI+Instrumentation.m */; }; - B767704F223AE5E400545C90 /* SFRestAPI+Instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = B767704A223AE5E400545C90 /* SFRestAPI+Instrumentation.h */; }; - B7677051223AE5E400545C90 /* SFUserAccountManager+Instrumentation.m in Sources */ = {isa = PBXBuildFile; fileRef = B767704B223AE5E400545C90 /* SFUserAccountManager+Instrumentation.m */; }; - B7677053223AE5E400545C90 /* SFUserAccountManager+Instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = B767704C223AE5E400545C90 /* SFUserAccountManager+Instrumentation.h */; }; B773CCF61F8200BD00D2D1B2 /* SFSDKIDPLoginRequestCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = B773CCF41F8200BD00D2D1B2 /* SFSDKIDPLoginRequestCommand.h */; }; B773CCF81F8200BD00D2D1B2 /* SFSDKIDPLoginRequestCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = B773CCF51F8200BD00D2D1B2 /* SFSDKIDPLoginRequestCommand.m */; }; - B78927622241643500BEDED4 /* SFSDKInstrumentationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B789272C2241569200BEDED4 /* SFSDKInstrumentationHelper.m */; }; B7895D0D2345015B00765D85 /* SFSDKCompositeRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = B7895D0B2345015B00765D85 /* SFSDKCompositeRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; B7895D0E2345015B00765D85 /* SFSDKCompositeRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7895D0C2345015B00765D85 /* SFSDKCompositeRequest.m */; }; B7895D1523450E8E00765D85 /* SFSDKCompositeRequest+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B7895D1323450E8E00765D85 /* SFSDKCompositeRequest+Internal.h */; }; @@ -258,7 +254,6 @@ B7C274561F81507100CE539D /* SFSDKSPLoginResponseCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = B7C274531F81507100CE539D /* SFSDKSPLoginResponseCommand.m */; }; B7C2745A1F8151E300CE539D /* SFSDKAuthErrorCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = B7C274581F8151E300CE539D /* SFSDKAuthErrorCommand.h */; }; B7C2745C1F8151E300CE539D /* SFSDKAuthErrorCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = B7C274591F8151E300CE539D /* SFSDKAuthErrorCommand.m */; }; - B7C4617122403E66009EB0B0 /* SFSDKInstrumentationHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = B7C4617022403E66009EB0B0 /* SFSDKInstrumentationHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; B7C5125920C188AE00B39DAA /* SFSDKViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B7C5125720C188AE00B39DAA /* SFSDKViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; B7C5125A20C188AE00B39DAA /* SFSDKViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7C5125820C188AE00B39DAA /* SFSDKViewController.m */; }; B7CD6D651F79CFC900F99F81 /* SFUserAccountManager+URLHandlers.h in Headers */ = {isa = PBXBuildFile; fileRef = B7CD6D631F79CFC900F99F81 /* SFUserAccountManager+URLHandlers.h */; }; @@ -332,10 +327,6 @@ CE4CE33B1C0E5245009F6029 /* SFIdentityCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FC661BFD32130022F021 /* SFIdentityCoordinator.m */; }; CE4CE33C1C0E5245009F6029 /* SFIdentityData.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FC671BFD32130022F021 /* SFIdentityData.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE4CE33D1C0E5245009F6029 /* SFIdentityData.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FC681BFD32130022F021 /* SFIdentityData.m */; }; - CE4CE33E1C0E524B009F6029 /* SFInstrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FC6A1BFD32130022F021 /* SFInstrumentation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CE4CE33F1C0E524B009F6029 /* SFInstrumentation.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FC6B1BFD32130022F021 /* SFInstrumentation.m */; }; - CE4CE3401C0E524B009F6029 /* SFMethodInterceptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FC6C1BFD32130022F021 /* SFMethodInterceptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CE4CE3411C0E524B009F6029 /* SFMethodInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FC6D1BFD32130022F021 /* SFMethodInterceptor.m */; }; CE4CE3421C0E5252009F6029 /* SFOAuthCoordinator+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FCC51BFD32130022F021 /* SFOAuthCoordinator+Internal.h */; }; CE4CE3431C0E5252009F6029 /* SFOAuthCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FCC61BFD32130022F021 /* SFOAuthCoordinator.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE4CE3441C0E5252009F6029 /* SFOAuthCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FCC71BFD32130022F021 /* SFOAuthCoordinator.m */; }; @@ -375,8 +366,6 @@ CE4CE3941C0E526A009F6029 /* SFUserAccountManager+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FD291BFD32140022F021 /* SFUserAccountManager+Internal.h */; }; CE4CE3951C0E526A009F6029 /* SFUserAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FD2A1BFD32140022F021 /* SFUserAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE4CE3961C0E526A009F6029 /* SFUserAccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FD2B1BFD32140022F021 /* SFUserAccountManager.m */; }; - CE4CE3991C0E5272009F6029 /* SFSDKAsyncProcessListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FD2F1BFD32140022F021 /* SFSDKAsyncProcessListener.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CE4CE39A1C0E5272009F6029 /* SFSDKAsyncProcessListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FD301BFD32140022F021 /* SFSDKAsyncProcessListener.m */; }; CE4CE39B1C0E5272009F6029 /* SFSDKTestCredentialsData.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FD311BFD32140022F021 /* SFSDKTestCredentialsData.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE4CE39C1C0E5272009F6029 /* SFSDKTestCredentialsData.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F96FD321BFD32140022F021 /* SFSDKTestCredentialsData.m */; }; CE4CE39D1C0E5272009F6029 /* SFSDKTestRequestListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F96FD331BFD32140022F021 /* SFSDKTestRequestListener.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -605,6 +594,7 @@ 4F3139672331C5B9007B3705 /* SFSDKAuthRootController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSDKAuthRootController.h; sourceTree = ""; }; 4F3ECD892EBBD150005020A6 /* SFOAuthCoordinatorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFOAuthCoordinatorTests.m; sourceTree = ""; }; 4F3ECD8B2EBBD182005020A6 /* SFOAuthInfoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFOAuthInfoTests.m; sourceTree = ""; }; + 4FA1B2C32F0E000000000002 /* LoginForAdminTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginForAdminTests.swift; sourceTree = ""; }; 4F5727DC27F27F1A0008CDA4 /* SFSDKPrimingRecordsResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSDKPrimingRecordsResponse.h; sourceTree = ""; }; 4F5727E227F27F1A0008CDA4 /* SFSDKPrimingRecordsResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSDKPrimingRecordsResponse.m; sourceTree = ""; }; 4F5A494F2E98711600C89DDD /* ScopeParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScopeParser.swift; sourceTree = ""; }; @@ -640,10 +630,6 @@ 4F96FC661BFD32130022F021 /* SFIdentityCoordinator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFIdentityCoordinator.m; sourceTree = ""; }; 4F96FC671BFD32130022F021 /* SFIdentityData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFIdentityData.h; sourceTree = ""; }; 4F96FC681BFD32130022F021 /* SFIdentityData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFIdentityData.m; sourceTree = ""; }; - 4F96FC6A1BFD32130022F021 /* SFInstrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFInstrumentation.h; sourceTree = ""; }; - 4F96FC6B1BFD32130022F021 /* SFInstrumentation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFInstrumentation.m; sourceTree = ""; }; - 4F96FC6C1BFD32130022F021 /* SFMethodInterceptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFMethodInterceptor.h; sourceTree = ""; }; - 4F96FC6D1BFD32130022F021 /* SFMethodInterceptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFMethodInterceptor.m; sourceTree = ""; }; 4F96FCC51BFD32130022F021 /* SFOAuthCoordinator+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SFOAuthCoordinator+Internal.h"; sourceTree = ""; }; 4F96FCC61BFD32130022F021 /* SFOAuthCoordinator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFOAuthCoordinator.h; sourceTree = ""; }; 4F96FCC71BFD32130022F021 /* SFOAuthCoordinator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFOAuthCoordinator.m; sourceTree = ""; }; @@ -683,8 +669,6 @@ 4F96FD291BFD32140022F021 /* SFUserAccountManager+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SFUserAccountManager+Internal.h"; sourceTree = ""; }; 4F96FD2A1BFD32140022F021 /* SFUserAccountManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFUserAccountManager.h; sourceTree = ""; }; 4F96FD2B1BFD32140022F021 /* SFUserAccountManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFUserAccountManager.m; sourceTree = ""; }; - 4F96FD2F1BFD32140022F021 /* SFSDKAsyncProcessListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSDKAsyncProcessListener.h; sourceTree = ""; }; - 4F96FD301BFD32140022F021 /* SFSDKAsyncProcessListener.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSDKAsyncProcessListener.m; sourceTree = ""; }; 4F96FD311BFD32140022F021 /* SFSDKTestCredentialsData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSDKTestCredentialsData.h; sourceTree = ""; }; 4F96FD321BFD32140022F021 /* SFSDKTestCredentialsData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSDKTestCredentialsData.m; sourceTree = ""; }; 4F96FD331BFD32140022F021 /* SFSDKTestRequestListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSDKTestRequestListener.h; sourceTree = ""; }; @@ -709,12 +693,12 @@ 4F9E05332DD7BE0A00548985 /* SFOAuthCredentialsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SFOAuthCredentialsTests.m; path = ../SalesforceSDKCoreTests/SFOAuthCredentialsTests.m; sourceTree = ""; }; 4FAUTHFLOW112345678901ABC /* AuthFlowTypesViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthFlowTypesViewTests.swift; path = SalesforceSDKCoreTests/AuthFlowTypesViewTests.swift; sourceTree = SOURCE_ROOT; }; 4FBOOTCP112345678901ABCD /* LoginOptionsViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoginOptionsViewControllerTests.swift; path = SalesforceSDKCoreTests/LoginOptionsViewControllerTests.swift; sourceTree = SOURCE_ROOT; }; - 4FDISCOV112345678901ABCD /* DiscoveryResultEditorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DiscoveryResultEditorTests.swift; path = SalesforceSDKCoreTests/DiscoveryResultEditorTests.swift; sourceTree = SOURCE_ROOT; }; 4FDEVINFO112345678901ABCD /* DevInfoViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DevInfoViewControllerTests.swift; path = SalesforceSDKCoreTests/DevInfoViewControllerTests.swift; sourceTree = SOURCE_ROOT; }; + 4FDISCOV112345678901ABCD /* DiscoveryResultEditorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DiscoveryResultEditorTests.swift; path = SalesforceSDKCoreTests/DiscoveryResultEditorTests.swift; sourceTree = SOURCE_ROOT; }; 4FE006AE2EBEB65900CFD66F /* BootConfigEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BootConfigEditor.swift; path = SalesforceSDKCore/Classes/Login/DevConfig/BootConfigEditor.swift; sourceTree = SOURCE_ROOT; }; 4FE006AF2EBEB65900CFD66F /* LoginOptionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoginOptionsViewController.swift; path = SalesforceSDKCore/Classes/Login/DevConfig/LoginOptionsViewController.swift; sourceTree = SOURCE_ROOT; }; - 4FE006B42EBEB65900CFD66F /* DiscoveryResultEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DiscoveryResultEditor.swift; path = SalesforceSDKCore/Classes/Login/DevConfig/DiscoveryResultEditor.swift; sourceTree = SOURCE_ROOT; }; 4FE006B02EBEB65900CFD66F /* AuthFlowTypesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthFlowTypesView.swift; path = SalesforceSDKCore/Classes/Login/DevConfig/AuthFlowTypesView.swift; sourceTree = SOURCE_ROOT; }; + 4FE006B42EBEB65900CFD66F /* DiscoveryResultEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DiscoveryResultEditor.swift; path = SalesforceSDKCore/Classes/Login/DevConfig/DiscoveryResultEditor.swift; sourceTree = SOURCE_ROOT; }; 4FE006CA2EBEBBF300CFD66F /* NewLoginHostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewLoginHostView.swift; sourceTree = ""; }; 4FE006CB2EBEBBF300CFD66F /* SFSDKLoginHost.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSDKLoginHost.h; sourceTree = ""; }; 4FE006CC2EBEBBF300CFD66F /* SFSDKLoginHost.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSDKLoginHost.m; sourceTree = ""; }; @@ -859,13 +843,8 @@ B759CD8A1F8C10DC0081AA87 /* SFSDKErrorManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SFSDKErrorManagerTests.m; path = SalesforceSDKCoreTests/SFSDKErrorManagerTests.m; sourceTree = SOURCE_ROOT; }; B767368F20A4AB0200F04103 /* SFSDKNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSDKNavigationController.h; sourceTree = ""; }; B767369020A4AB0200F04103 /* SFSDKNavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSDKNavigationController.m; sourceTree = ""; }; - B7677043223AE5E400545C90 /* SFRestAPI+Instrumentation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SFRestAPI+Instrumentation.m"; sourceTree = ""; }; - B767704A223AE5E400545C90 /* SFRestAPI+Instrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SFRestAPI+Instrumentation.h"; sourceTree = ""; }; - B767704B223AE5E400545C90 /* SFUserAccountManager+Instrumentation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SFUserAccountManager+Instrumentation.m"; sourceTree = ""; }; - B767704C223AE5E400545C90 /* SFUserAccountManager+Instrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SFUserAccountManager+Instrumentation.h"; sourceTree = ""; }; B773CCF41F8200BD00D2D1B2 /* SFSDKIDPLoginRequestCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSDKIDPLoginRequestCommand.h; sourceTree = ""; }; B773CCF51F8200BD00D2D1B2 /* SFSDKIDPLoginRequestCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSDKIDPLoginRequestCommand.m; sourceTree = ""; }; - B789272C2241569200BEDED4 /* SFSDKInstrumentationHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSDKInstrumentationHelper.m; sourceTree = ""; }; B7895D0B2345015B00765D85 /* SFSDKCompositeRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSDKCompositeRequest.h; sourceTree = ""; }; B7895D0C2345015B00765D85 /* SFSDKCompositeRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSDKCompositeRequest.m; sourceTree = ""; }; B7895D1323450E8E00765D85 /* SFSDKCompositeRequest+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFSDKCompositeRequest+Internal.h"; sourceTree = ""; }; @@ -902,7 +881,6 @@ B7C274531F81507100CE539D /* SFSDKSPLoginResponseCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSDKSPLoginResponseCommand.m; sourceTree = ""; }; B7C274581F8151E300CE539D /* SFSDKAuthErrorCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSDKAuthErrorCommand.h; sourceTree = ""; }; B7C274591F8151E300CE539D /* SFSDKAuthErrorCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSDKAuthErrorCommand.m; sourceTree = ""; }; - B7C4617022403E66009EB0B0 /* SFSDKInstrumentationHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSDKInstrumentationHelper.h; sourceTree = ""; }; B7C5125720C188AE00B39DAA /* SFSDKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSDKViewController.h; sourceTree = ""; }; B7C5125820C188AE00B39DAA /* SFSDKViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSDKViewController.m; sourceTree = ""; }; B7CD6D631F79CFC900F99F81 /* SFUserAccountManager+URLHandlers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SFUserAccountManager+URLHandlers.h"; sourceTree = ""; }; @@ -1100,6 +1078,7 @@ 4F7EB3F81BFFC87600768720 /* SFEncryptionKeyTests.m */, B7352CA422761D8400DA2CFF /* SFManagedPreferencesTest.m */, 69CEBC7D22F368CF00F16218 /* SFNetworkTests.m */, + 4FA1B2C32F0E000000000002 /* LoginForAdminTests.swift */, 4F3ECD892EBBD150005020A6 /* SFOAuthCoordinatorTests.m */, 23EED8892E2ACD3300646B10 /* SFOAuthCoordinatorTests.swift */, 4F9E05332DD7BE0A00548985 /* SFOAuthCredentialsTests.m */, @@ -1209,23 +1188,6 @@ path = Identity; sourceTree = ""; }; - 4F96FC691BFD32130022F021 /* Instrumentation */ = { - isa = PBXGroup; - children = ( - B789272C2241569200BEDED4 /* SFSDKInstrumentationHelper.m */, - B7C4617022403E66009EB0B0 /* SFSDKInstrumentationHelper.h */, - B767704A223AE5E400545C90 /* SFRestAPI+Instrumentation.h */, - B7677043223AE5E400545C90 /* SFRestAPI+Instrumentation.m */, - B767704C223AE5E400545C90 /* SFUserAccountManager+Instrumentation.h */, - B767704B223AE5E400545C90 /* SFUserAccountManager+Instrumentation.m */, - 4F96FC6A1BFD32130022F021 /* SFInstrumentation.h */, - 4F96FC6B1BFD32130022F021 /* SFInstrumentation.m */, - 4F96FC6C1BFD32130022F021 /* SFMethodInterceptor.h */, - 4F96FC6D1BFD32130022F021 /* SFMethodInterceptor.m */, - ); - path = Instrumentation; - sourceTree = ""; - }; 4F96FCC41BFD32130022F021 /* OAuth */ = { isa = PBXGroup; children = ( @@ -1300,8 +1262,6 @@ 4F96FD2E1BFD32140022F021 /* Test */ = { isa = PBXGroup; children = ( - 4F96FD2F1BFD32140022F021 /* SFSDKAsyncProcessListener.h */, - 4F96FD301BFD32140022F021 /* SFSDKAsyncProcessListener.m */, 4F96FD311BFD32140022F021 /* SFSDKTestCredentialsData.h */, 4F96FD321BFD32140022F021 /* SFSDKTestCredentialsData.m */, 4F96FD331BFD32140022F021 /* SFSDKTestRequestListener.h */, @@ -1526,7 +1486,6 @@ B722A702233C432E0089736E /* Extensions */, 4F96FC631BFD32130022F021 /* Identity */, B7FB26B51F78094A00FB25A2 /* IDP */, - 4F96FC691BFD32130022F021 /* Instrumentation */, E139509E1C535F9C00575C03 /* Login */, 4F96FCC41BFD32130022F021 /* OAuth */, 4F96FCD81BFD32130022F021 /* PushNotification */, @@ -1848,12 +1807,10 @@ CE4CE3431C0E5252009F6029 /* SFOAuthCoordinator.h in Headers */, B7C5125920C188AE00B39DAA /* SFSDKViewController.h in Headers */, B7895D192345304800765D85 /* SFSDKCompositeResponse.h in Headers */, - CE4CE3991C0E5272009F6029 /* SFSDKAsyncProcessListener.h in Headers */, CE4CE3251C0E523B009F6029 /* UIScreen+SFAdditions.h in Headers */, CE4CE38E1C0E526A009F6029 /* SFUserAccount.h in Headers */, B7FB26C71F78094A00FB25A2 /* SFSDKUserSelectionTableViewController.h in Headers */, B72171562353BFF20022510F /* SFSDKAuthRequest.h in Headers */, - CE4CE33E1C0E524B009F6029 /* SFInstrumentation.h in Headers */, 4F06AF811C49A16A00F70798 /* SFOAuthTestFlowCoordinatorDelegate.h in Headers */, CE4CE34C1C0E5252009F6029 /* SFOAuthKeychainCredentials.h in Headers */, CE4CE39F1C0E5272009F6029 /* TestSetupUtils.h in Headers */, @@ -1874,7 +1831,6 @@ CE4CE3A11C0E5279009F6029 /* NSURL+SFStringUtils.h in Headers */, CED452B91D808D0C009266EB /* SFRestAPI+Files.h in Headers */, CED452C31D808D0C009266EB /* SFRestRequest.h in Headers */, - CE4CE3401C0E524B009F6029 /* SFMethodInterceptor.h in Headers */, B7C2745A1F8151E300CE539D /* SFSDKAuthErrorCommand.h in Headers */, B7FB26E31F78096300FB25A2 /* SFSDKURLHandlerManager.h in Headers */, CE4CE3091C0E523B009F6029 /* NSURL+SFAdditions.h in Headers */, @@ -1886,7 +1842,6 @@ B7FB26C91F78094A00FB25A2 /* SFSDKUserSelectionView.h in Headers */, 6938392623C82F38008E8E9A /* SFSDKNullURLCache.h in Headers */, CED452B71D808D0C009266EB /* SFRestAPI+Blocks.h in Headers */, - B767704F223AE5E400545C90 /* SFRestAPI+Instrumentation.h in Headers */, 697A91A02363C3D800D2836F /* SFSDKPushNotificationDecryption.h in Headers */, B7E8A2A51E7369DB007C0D92 /* SFDefaultUserAccountPersister.h in Headers */, CE4CE3941C0E526A009F6029 /* SFUserAccountManager+Internal.h in Headers */, @@ -1967,14 +1922,12 @@ CED452C21D808D0C009266EB /* SFRestRequest+Internal.h in Headers */, CE4CE3A31C0E5279009F6029 /* SalesforceSDKCoreDefines.h in Headers */, 69848CA52363F8AF00893E57 /* SFSDKPushNotificationFieldsConstants.h in Headers */, - B7C4617122403E66009EB0B0 /* SFSDKInstrumentationHelper.h in Headers */, 695E86B929EF8D6E002BDEA6 /* SFSDKIDPAuthCodeLoginRequestCommand.h in Headers */, CE4CE3651C0E526A009F6029 /* SFDefaultUserManagementDetailViewController.h in Headers */, B7FB26DC1F78096300FB25A2 /* SFSDKIDPLoginRequestHandler.h in Headers */, CE4CE3231C0E523B009F6029 /* UIDevice+SFHardware.h in Headers */, 69848CB52363FA3E00893E57 /* SFSDKPushNotificationError.h in Headers */, CE4CE3381C0E5245009F6029 /* SFIdentityData+Internal.h in Headers */, - B7677053223AE5E400545C90 /* SFUserAccountManager+Instrumentation.h in Headers */, 4F06AF751C49A16A00F70798 /* SalesforceOAuthUnitTests.h in Headers */, CE4CE3421C0E5252009F6029 /* SFOAuthCoordinator+Internal.h in Headers */, CED452BC1D808D0C009266EB /* SFRestAPI+QueryBuilder.h in Headers */, @@ -2295,6 +2248,7 @@ 4F7EB41B1BFFC8D700768720 /* SFSDKCryptoUtilsTests.m in Sources */, 69848CB82364035300893E57 /* SFSDKEncryptedPushNotificationTests.m in Sources */, 4F3ECD8A2EBBD150005020A6 /* SFOAuthCoordinatorTests.m in Sources */, + 4FA1B2C32F0E000000000001 /* LoginForAdminTests.swift in Sources */, 4F9E05322DD6A08000548985 /* SFSDKOAuthTokenEndpointResponseTests.m in Sources */, 4F06AF8D1C49A18E00F70798 /* SalesforceSDKManagerTests.m in Sources */, 237C186C2E44FCAE0008015C /* EncryptStreamTests.swift in Sources */, @@ -2352,7 +2306,6 @@ B72171572353BFF20022510F /* SFSDKAuthRequest.m in Sources */, B78A238D21014FCA00B19AB3 /* SFSDKAuthHelper.m in Sources */, A3C7475F29F7087B00D72B7F /* BiometricAuthenticationManager.swift in Sources */, - CE4CE33F1C0E524B009F6029 /* SFInstrumentation.m in Sources */, 4FE006B12EBEB65900CFD66F /* AuthFlowTypesView.swift in Sources */, 4FE006B22EBEB65900CFD66F /* BootConfigEditor.swift in Sources */, 4FE006B32EBEB65900CFD66F /* LoginOptionsViewController.swift in Sources */, @@ -2368,7 +2321,6 @@ CE4CE3881C0E526A009F6029 /* SFSDKCryptoUtils.m in Sources */, CE4CE3261C0E523B009F6029 /* UIScreen+SFAdditions.m in Sources */, B7C273F01F7EEFB700CE539D /* SFSDKIDPConstants.m in Sources */, - B767704D223AE5E400545C90 /* SFRestAPI+Instrumentation.m in Sources */, D3D675DB2D39EF01008E468E /* ChatGenerationsRequestBody.swift in Sources */, D3D675DC2D39EF01008E468E /* EmbeddingsRequestBody.swift in Sources */, D3D675DD2D39EF01008E468E /* ChatGenerationsResponseBody.swift in Sources */, @@ -2395,7 +2347,6 @@ CE4CE3AA1C0E5279009F6029 /* SFManagedPreferences.m in Sources */, CE4CE35E1C0E526A009F6029 /* SFAuthErrorHandler.m in Sources */, B722A709233C437E0089736E /* RestClient.swift in Sources */, - CE4CE3411C0E524B009F6029 /* SFMethodInterceptor.m in Sources */, 69BDD7EA26F16C9000C26D77 /* SFSDKSalesforceSDKUpgradeManager.m in Sources */, E1C80CE01C5AEBFA001B3A21 /* SFLoginViewController.m in Sources */, 693E623124A287DB0017B222 /* KeyValueEncryptedFileStore.swift in Sources */, @@ -2405,7 +2356,6 @@ B7CD6D671F79CFC900F99F81 /* SFUserAccountManager+URLHandlers.m in Sources */, 69848CB62363FA3E00893E57 /* SFSDKPushNotificationError.m in Sources */, 23CAB1312DD515B500B8929B /* SFLoginViewController+Deep-Linking.swift in Sources */, - CE4CE39A1C0E5272009F6029 /* SFSDKAsyncProcessListener.m in Sources */, B7A20F861F25850E00D1E4B0 /* SFSDKWindowContainer.m in Sources */, B7FB26C41F78094A00FB25A2 /* SFSDKLoginFlowSelectionViewController.m in Sources */, CE4CE36D1C0E526A009F6029 /* SFEncryptionKey.m in Sources */, @@ -2419,7 +2369,6 @@ CE675A361E0B2CC6002DBF5A /* SFSDKSoslBuilder.m in Sources */, 69DFE0632B968D8F000906E4 /* CryptoUtils.swift in Sources */, FDED97291CAA16EB009D80F2 /* SFApplicationHelper.m in Sources */, - B78927622241643500BEDED4 /* SFSDKInstrumentationHelper.m in Sources */, CE4CE39E1C0E5272009F6029 /* SFSDKTestRequestListener.m in Sources */, 23705EC22DF35D6C00E644A0 /* WebSocketClient.swift in Sources */, B7E1A7851F4C8844007AC36A /* SFSDKAuthViewHandler.m in Sources */, @@ -2494,7 +2443,6 @@ A3C7476129F709EB00D72B7F /* BiometricAuthenticationManagerInternal.swift in Sources */, B7FB26DB1F78096300FB25A2 /* SFSDKIDPErrorHandler.m in Sources */, 4F5A49502E98711600C89DDD /* ScopeParser.swift in Sources */, - B7677051223AE5E400545C90 /* SFUserAccountManager+Instrumentation.m in Sources */, B773CCF81F8200BD00D2D1B2 /* SFSDKIDPLoginRequestCommand.m in Sources */, CE4CE3931C0E526A009F6029 /* SFUserAccountIdentity.m in Sources */, 23945B712D78E4A60060B195 /* NotificationType.swift in Sources */, @@ -2679,7 +2627,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; @@ -2718,7 +2666,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_VERSION = 5.0; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKConstants.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKConstants.h index 6f1a92a050..d8d087d559 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKConstants.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKConstants.h @@ -1,7 +1,7 @@ #ifndef SalesforceSDKConstants_h #define SalesforceSDKConstants_h -#define SALESFORCE_SDK_IS_PRODUCTION_VERSION YES +#define SALESFORCE_SDK_IS_PRODUCTION_VERSION NO #define SALESFORCE_SDK_BUILD_IDENTIFIER @".dev" @@ -87,7 +87,9 @@ #define __SALESFORCE_SDK_13_2_0 130200 -#define SALESFORCE_SDK_VERSION_MIN_REQUIRED __SALESFORCE_SDK_13_2_0 +#define __SALESFORCE_SDK_14_0_0 140000 + +#define SALESFORCE_SDK_VERSION_MIN_REQUIRED __SALESFORCE_SDK_14_0_0 #define SALESFORCE_SDK_VERSION [NSString stringWithFormat:@"%d.%d.%d%@", \ (SALESFORCE_SDK_VERSION_MIN_REQUIRED / 10000), \ @@ -116,57 +118,4 @@ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") #define SFSDK_USE_DEPRECATED_END \ _Pragma("clang diagnostic pop") - -/*! - * @function sf_os_signpost_interval_begin - * - * @abstract - * Begins a signpost interval. - * - * @param log - * Log handle previously created with `os_log_create`. - * - * @param interval_id - * An ID for the event. See Signpost IDs. - * - * @param name - * The name of this event. Must be a hard-coded string. - * - * @param ... (format + arguments) - * Additional information to include with this signpost. - * Must be a hard-coded string, as required by `os_log` functions. - */ -#define sf_os_signpost_interval_begin(log, interval_id, name, ...) \ - os_signpost_emit_with_type(log, OS_SIGNPOST_INTERVAL_BEGIN, interval_id, name, ##__VA_ARGS__); - - -/*! - * @function sf_os_signpost_interval_end - * - * @abstract - * Ends a signpost interval. - * - * @param log - * Log handle provided to `os_signpost_interval_begin`. - * - * @param interval_id - * Event ID provided to `os_signpost_interval_begin`. See - * Signpost IDs. - * - * @param name - * Event name provided to 'os_signost_interval_begin'. Must be a - * hard-coded string. - * - * @param ... (format + arguments) - * Additional information to include with this signpost. Must be a hard-coded string, as required by `os_log` functions. - */ -#define sf_os_signpost_interval_end(log, interval_id, name, ...) \ - os_signpost_emit_with_type(log, OS_SIGNPOST_INTERVAL_END, interval_id, name, ##__VA_ARGS__); - -#define sf_os_signpost_id_generate(log) \ -({ os_signpost_id_t sid = OS_SIGNPOST_ID_INVALID; \ - sid = os_signpost_id_generate(log); \ - sid; \ -}) - #endif // SalesforceSDKConstants_h diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIDevice+SFHardware.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIDevice+SFHardware.m index efc02fa8d1..afce5c7456 100755 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIDevice+SFHardware.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/UIDevice+SFHardware.m @@ -233,7 +233,7 @@ - (UIDevicePlatform)sfsdk_platformType { } } - // iPhones (iOS 17 and newer supported) + // iPhones (iOS 18 and newer supported) NSDictionary *iphoneIdentifiers = @{ @"iPhone12,8": @(UIDeviceSE2iPhone), // iPhone SE (2nd generation) @"iPhone14,6": @(UIDeviceSE3iPhone), // iPhone SE (3rd generation) @@ -268,7 +268,7 @@ - (UIDevicePlatform)sfsdk_platformType { NSNumber *iphoneType = iphoneIdentifiers[platform]; if (iphoneType) return iphoneType.integerValue; - // iPads (iOS 17 and newer supported) + // iPads (iOS 18 and newer supported) NSDictionary *ipadIdentifiers = @{ @"iPad7,11": @(UIDevice7GiPad), // iPad (7th generation) @"iPad7,12": @(UIDevice7GiPad), // iPad (7th generation) diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/WebViewStateManager.swift b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/WebViewStateManager.swift index c670fd75c4..7b78abe249 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/WebViewStateManager.swift +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/WebViewStateManager.swift @@ -36,20 +36,6 @@ public class SFSDKWebViewStateManager: NSObject { } } - @objc - @MainActor - @available(*, deprecated, renamed: "resetSessionCookie", message: "Deprecated in Salesforce Mobile SDK 13.2 and will be removed in Salesforce Mobile SDK 14.0. Use resetSessionCookie instead.") - public static func removeSession() { - if sessionCookieManagementDisabled { - SFSDKCoreLogger.d(SFSDKWebViewStateManager.self, message: "[\(Self.self) removeSession]: Cookie Management disabled. Will do nothing.") - return - } - - Task { - await removeWKWebViewCookies() - } - } - @objc @MainActor public static func resetSessionCookie() { @@ -93,20 +79,6 @@ public class SFSDKWebViewStateManager: NSObject { await removeWKWebViewCookies() } - - @available(*, deprecated, message: "Deprecated in Salesforce Mobile SDK 13.2 and will be removed in Salesforce Mobile SDK 14.0. WKProcessPool creation has no effect on iOS 15+ and this property will be removed.") - @objc - @MainActor - public static var sharedProcessPool: WKProcessPool? { - get { - // WKProcessPool creation is deprecated since iOS 15 and has no effect. - return nil - } - set { - // Do nothing - } - } - @MainActor private static func removeWKWebViewCookies() async { let dataStore = WKWebsiteDataStore.default() diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFInstrumentation.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFInstrumentation.h deleted file mode 100644 index 3ae86c4a3c..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFInstrumentation.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright (c) 2015-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 -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef BOOL (^SFInstrumentationSelectorFilter)(SEL selector, BOOL isInstanceSelector); - - -/** This class exposes API that allow to intercept - method call and introspect the object being intercepted. - It can be used to record timing & usage information for example. - */ -/// @deprecated SFInstrumentation is deprecated and this class will be removed in version 14.0. -SFSDK_DEPRECATED(13.2, 14.0, "SFInstrumentation is deprecated and will be removed."); -@interface SFInstrumentation : NSObject - -/** Enable or disable this instrumentation instance - */ -@property (nonatomic) BOOL enabled; - -/** Returns an instrumentation instance for the specified class - @param clazz The class to be instrumented - */ -+ (instancetype)instrumentationForClass:(Class)clazz; - -/** Returns an instrumentation instance for the class with the specified name. - @param className The name of the class to be instrumented. - */ -+ (instancetype)instrumentationForClassWithName:(NSString *)className; - -/** Returns the interceptor configured for the class with the given selector, or `nil` - if an interceptor is not configured for the given selector. - @param selector The selector to check - @param isInstanceSelector Whether or not the selector is an instance selector. - @return The configured `SFMethodInterceptor` instance, or `nil` if an interceptor is - not configured. - */ -- (nullable SFMethodInterceptor *)interceptorForSelector:(SEL)selector isInstanceSelector:(BOOL)isInstanceSelector; - -/** Use this method to intercept the instance method specified by `selector` - @param selector The selector to intercept - @param before An optional block invoked before the selector is executed - @param after An optional block invoked after the selector is executed - */ -- (void)interceptInstanceMethod:(SEL)selector beforeBlock:(nullable SFMethodInterceptorInvocationCallback)before afterBlock:(nullable SFMethodInterceptorInvocationAfterCallback)after; - -/** Use this method to intercept the instance method specified by `selector` - and provide a block that will be invoked instead of the method. - Note: the block contains a single argument which is the NSInvocation of the message. - @param selector The instance method to be intercepted - @param replace The block to be invoked - */ -- (void)interceptInstanceMethod:(SEL)selector replaceWithInvocationBlock:(nullable SFMethodInterceptorInvocationCallback)replace; - -/** Use this method to intercept the class method specified by `selector` - @param selector The selector to intercept - @param before An optional block invoked before the selector is executed - @param after An optional block invoked after the selector is executed - */ -- (void)interceptClassMethod:(SEL)selector beforeBlock:(nullable SFMethodInterceptorInvocationCallback)before afterBlock:(nullable SFMethodInterceptorInvocationAfterCallback)after; - -/** Use this method to intercept the class method specified by `selector` - and provide a block that will be invoked instead of the method. - Note: the block contains a single argument which is the NSInvocation of the message. - @param selector The instance method to be intercepted - @param replace The block to be invoked - */ -- (void)interceptClassMethod:(SEL)selector replaceWithInvocationBlock:(SFMethodInterceptorInvocationCallback)replace; - -/** Instrument some selectors of a the target class for performance timing. - @param selectorFilter A block invoked when to select selectors from the class to instrument - @param after An optional block invoked after any selector is executed - @discussion This method will only instrument selectors defined on or explicitly overridden - in the class. To instrument inherited selectors, use the - instrumentForTiming:inheritanceLevels:afterBlock: overload. Calling this method is - the same as calling instrumentForTiming:inheritanceLevels:afterBlock: with an - inheritance levels value of zero. - */ --(void)instrumentForTiming:(SFInstrumentationSelectorFilter)selectorFilter afterBlock:(SFMethodInterceptorInvocationAfterCallback)after; - -/** Instrument some selectors of the target class and its parent class(es) - for performance timing. - @param selectorFilter A block invoked when to select selectors from the class to instrument - @param numInheritanceLevels The number of inherited classes whose selectors will be made available. - @param after An optional block invoked after any selector is executed - */ -- (void)instrumentForTiming:(SFInstrumentationSelectorFilter)selectorFilter - inheritanceLevels:(NSUInteger)numInheritanceLevels - afterBlock:(SFMethodInterceptorInvocationAfterCallback)after; - -/** Loads the array of instructions execute them. The instructions usually - comes from a JSON file. - @param instructions The array of instructions - @param completion Optional completion block - */ -- (void)loadInstructions:(NSArray*)instructions completion:(dispatch_block_t)completion; - -/** Start the timing measurement - */ -- (void)startMeasure; - -/** Stop the timing measurement - */ -- (void)stopMeasure; - - -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFInstrumentation.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFInstrumentation.m deleted file mode 100644 index 1eff95f53d..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFInstrumentation.m +++ /dev/null @@ -1,278 +0,0 @@ -/* - Copyright (c) 2015-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 "SFInstrumentation.h" -#import "SFMethodInterceptor.h" -#import - -@interface SFInstrumentation () - -@property (nonatomic) Class clazz; - -@property (nonatomic, strong) NSMutableArray *interceptors; - -@property (nonatomic, strong) NSMutableDictionary *collector; - -@property (nonatomic, strong) NSString *sessionKey; -@property (nonatomic, strong) NSString *sessionValue; - -@property (nonatomic) NSTimeInterval startTime; -@property (nonatomic) NSTimeInterval endTime; - -@end - -@implementation SFInstrumentation - -+ (instancetype)instrumentationForClass:(Class)clazz { - SFInstrumentation *perf = [[SFInstrumentation alloc] init]; - perf.clazz = clazz; - return perf; -} - -+ (instancetype)instrumentationForClassWithName:(NSString *)className { - NSAssert(className.length > 0, @"Class name cannot be empty."); - Class classToInstrument = NSClassFromString(className); - NSAssert(classToInstrument != nil, @"Class '%@' does not exist.", className); - return [self instrumentationForClass:classToInstrument]; -} - -- (instancetype)init { - self = [super init]; - if (self) { - self.interceptors = [NSMutableArray array]; - self.collector = [NSMutableDictionary dictionary]; - } - return self; -} - -- (SFMethodInterceptor *)interceptorForSelector:(SEL)selector isInstanceSelector:(BOOL)isInstanceSelector { - NSUInteger interceptorIndex = [self.interceptors indexOfObjectPassingTest:^BOOL(SFMethodInterceptor *obj, NSUInteger idx, BOOL *stop) { - return (obj.classToIntercept == self.clazz && obj.selectorToIntercept == selector && obj.instanceMethod == isInstanceSelector); - }]; - return (interceptorIndex == NSNotFound ? nil : self.interceptors[interceptorIndex]); -} - -- (void)setEnabled:(BOOL)enabled { - if (_enabled != enabled) { - [self willChangeValueForKey:@"enabled"]; - _enabled = enabled; - for (SFMethodInterceptor *interceptor in self.interceptors) { - interceptor.enabled = enabled; - } - [self didChangeValueForKey:@"enabled"]; - } -} - -- (void)interceptInstanceMethod:(SEL)selector beforeBlock:(SFMethodInterceptorInvocationCallback)before afterBlock:(SFMethodInterceptorInvocationAfterCallback)after { - [self interceptMethod:selector beforeBlock:before afterBlock:after isInstanceMethod:YES]; -} - -- (void)interceptInstanceMethod:(SEL)selector replaceWithInvocationBlock:(SFMethodInterceptorInvocationCallback)replace { - [self interceptMethod:selector replaceWithInvocationBlock:replace isInstanceMethod:YES]; -} - -- (void)interceptClassMethod:(SEL)selector beforeBlock:(SFMethodInterceptorInvocationCallback)before afterBlock:(SFMethodInterceptorInvocationAfterCallback)after { - [self interceptMethod:selector beforeBlock:before afterBlock:after isInstanceMethod:NO]; -} - -- (void)interceptClassMethod:(SEL)selector replaceWithInvocationBlock:(SFMethodInterceptorInvocationCallback)replace { - [self interceptMethod:selector replaceWithInvocationBlock:replace isInstanceMethod:NO]; -} - -- (void)interceptMethod:(SEL)selector - beforeBlock:(SFMethodInterceptorInvocationCallback)before - afterBlock:(SFMethodInterceptorInvocationAfterCallback)after - isInstanceMethod:(BOOL)isInstanceMethod { - SFMethodInterceptor *interceptor = [[SFMethodInterceptor alloc] init]; - interceptor.classToIntercept = self.clazz; - interceptor.selectorToIntercept = selector; - interceptor.targetBeforeBlock = before; - interceptor.targetAfterBlock = after; - interceptor.instanceMethod = isInstanceMethod; - if (![self.interceptors containsObject:interceptor]) { - interceptor.enabled = YES; - [self.interceptors addObject:interceptor]; - } else { - [SFSDKCoreLogger w:[self class] format:@"Interceptor with class '%@' and %@ selector '%@' is already configured. No action taken.", NSStringFromClass(self.clazz), (isInstanceMethod ? @"instance" : @"class"), NSStringFromSelector(selector)]; - } -} - -- (void)interceptMethod:(SEL)selector -replaceWithInvocationBlock:(SFMethodInterceptorInvocationCallback)replace - isInstanceMethod:(BOOL)isInstanceMethod { - SFMethodInterceptor *interceptor = [[SFMethodInterceptor alloc] init]; - interceptor.classToIntercept = self.clazz; - interceptor.selectorToIntercept = selector; - interceptor.targetReplaceBlock = replace; - interceptor.instanceMethod = isInstanceMethod; - if (![self.interceptors containsObject:interceptor]) { - interceptor.enabled = YES; - [self.interceptors addObject:interceptor]; - } else { - [SFSDKCoreLogger w:[self class] format:@"Interceptor with class '%@' and %@ selector '%@' is already configured. No action taken.", NSStringFromClass(self.clazz), (isInstanceMethod ? @"instance" : @"class"), NSStringFromSelector(selector)]; - } -} - -- (void)instrumentForTiming:(SFInstrumentationSelectorFilter)selectorFilter afterBlock:(SFMethodInterceptorInvocationAfterCallback)after { - [self instrumentForTiming:selectorFilter inheritanceLevels:0 afterBlock:after]; -} - -- (void)instrumentForTiming:(SFInstrumentationSelectorFilter)selectorFilter - inheritanceLevels:(NSUInteger)numInheritanceLevels - afterBlock:(SFMethodInterceptorInvocationAfterCallback)after { - if (after == nil) { - after = [self defaultPostTimingBlock]; - } - - NSMutableDictionary *configuredSelectorsDict = [NSMutableDictionary dictionary]; - NSUInteger currentInheritanceLevel = 0; - Class currentClass = self.clazz; - while (currentInheritanceLevel <= numInheritanceLevels && currentClass != nil) { - // Instance methods - unsigned int mc = 0; - Method *instanceMethodList = class_copyMethodList(currentClass, &mc); - for(NSUInteger i = 0; i < mc; i++) { - SEL selector = method_getName(instanceMethodList[i]); - NSString *selectorName = [NSString stringWithFormat:@"%@_%@", NSStringFromSelector(selector), @"inst"]; - if (configuredSelectorsDict[selectorName] == nil && selectorFilter(selector, YES)) { - configuredSelectorsDict[selectorName] = @YES; - [self interceptInstanceMethod:selector beforeBlock:nil afterBlock:after]; - } - } - - // Class methods - mc = 0; - Method *classMethodList = class_copyMethodList(object_getClass(currentClass), &mc); - for(NSUInteger i = 0; i < mc; i++) { - SEL selector = method_getName(classMethodList[i]); - NSString *selectorName = [NSString stringWithFormat:@"%@_%@", NSStringFromSelector(selector), @"class"]; - if (configuredSelectorsDict[selectorName] == nil && selectorFilter(selector, NO)) { - configuredSelectorsDict[selectorName] = @YES; - [self interceptClassMethod:selector beforeBlock:nil afterBlock:after]; - } - } - - currentInheritanceLevel++; - currentClass = [currentClass superclass]; - } -} - -- (SFMethodInterceptorInvocationAfterCallback)defaultPostTimingBlock { - __weak __typeof(self) weakSelf = self; - return ^(NSInvocation *invocation, SFSDKInstrumentationPostExecutionData *data) { - __strong __typeof(self) strongSelf = weakSelf; - [SFSDKCoreLogger i:[strongSelf class] - format:@"TIMING %@.%@: %.3f ms", NSStringFromClass(strongSelf.clazz), data.selectorName, data.executionTime*1000]; - }; -} - -#pragma mark - Driven - -- (void)loadInstructions:(NSArray*)instructions completion:(dispatch_block_t)completion { - for (NSDictionary *instruction in instructions) { - self.clazz = NSClassFromString(instruction[@"class"]); - NSDictionary *session = instruction[@"session"]; - if (session) { - self.sessionKey = session.allKeys[0]; - self.sessionValue = session.allValues[0]; - } - - for (NSDictionary *interceptor in instruction[@"intercept"]) { - SEL selector = NSSelectorFromString(interceptor[@"selector"]); - NSString *action = interceptor[@"action"]; - NSArray *keys = interceptor[@"keys"]; - - [self interceptInstanceMethod:selector beforeBlock:^(NSInvocation *invocation) { - if ([self isInstanceSession:invocation.target]) { - [self collectKeys:keys invocation:invocation selector:selector]; - if ([action isEqualToString:@"start"]) { - [self startMeasure]; - } - if ([action isEqualToString:@"end"]) { - [self stopMeasure]; - if (completion) completion(); - } - } - } afterBlock:nil]; - } - - self.enabled = YES; - } -} - -- (BOOL)isInstanceSession:(id)instance { - if (nil == self.sessionKey) { - return YES; - } - - id value = [instance valueForKey:self.sessionKey]; - return [self.sessionValue isEqualToString:[value description]]; -} - -- (void)collectKeys:(NSArray*)keys invocation:(NSInvocation*)invocation selector:(SEL)selector { - if (nil == keys) { - return; - } - - id instance = invocation.target; - - NSMutableDictionary *collection = [NSMutableDictionary dictionary]; - - NSMutableArray *args = [NSMutableArray array]; - for (NSUInteger index=2; index", NSStringFromClass([self class]), self, self.endTime-self.startTime, self.collector]; -} - -@end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFMethodInterceptor.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFMethodInterceptor.h deleted file mode 100644 index a83ad7e5a9..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFMethodInterceptor.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - Copyright (c) 2015-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 - -NS_ASSUME_NONNULL_BEGIN - -/** Class containing the perf data associated with a selector execution. - */ -@interface SFSDKInstrumentationPostExecutionData : NSObject - -/** The name of the class associated with the selector. - */ -@property (nonatomic, copy) NSString *className; - -/** The name of the original selector executed. - */ -@property (nonatomic, copy) NSString *selectorName; - -/** Whether or not the selector is an instance method. - */ -@property (nonatomic, assign) BOOL isInstanceMethod; - -/** The start date of the selector's execution. - */ -@property (nonatomic, strong) NSDate *executionStartDate; - -/** The end date of the selector's execution. - */ -@property (nonatomic, strong) NSDate *executionEndDate; - -/** The amount of execution time for the selector, in seconds. - */ -@property (nonatomic, assign) NSTimeInterval executionTime; - -@end - -typedef void(^SFMethodInterceptorInvocationCallback)(NSInvocation *invocation); -typedef void(^SFMethodInterceptorInvocationAfterCallback)(NSInvocation *invocation, SFSDKInstrumentationPostExecutionData *data); - -/** This class provides a simple way to intercept an - instance method or a class method and forward message - to the original method if needed. - */ -/// @deprecated SFMethodInterceptor is deprecated and this class will be removed in version 14.0. -SFSDK_DEPRECATED(13.2, 14.0, "Signpost logging is deprecated and will be removed."); -@interface SFMethodInterceptor : NSObject - -/** Class to intercept -*/ -@property (nonatomic, strong) Class classToIntercept; - -/** Selector to intercept -*/ -@property (nonatomic) SEL selectorToIntercept; - -/** YES if the `selectorToIntercept` is an instance -* method, NO if it's a class method. -*/ -@property (nonatomic) BOOL instanceMethod; - -// The various blocks of interceptions (each of them can be nil) -/** Block to be called before the target method. Can be nil. - */ -@property (nonatomic, copy) SFMethodInterceptorInvocationCallback targetBeforeBlock; -/** Block that replaces the target method. Can be nil. - */ -@property (nonatomic, copy) SFMethodInterceptorInvocationCallback targetReplaceBlock; -/** Block to be called after the target method. Can be nil. - */ -@property (nonatomic, copy) SFMethodInterceptorInvocationAfterCallback targetAfterBlock; - -/** Set this property to YES to enable the interceptor. -*/ -@property (nonatomic) BOOL enabled; - -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFMethodInterceptor.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFMethodInterceptor.m deleted file mode 100644 index 099e2b3202..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFMethodInterceptor.m +++ /dev/null @@ -1,295 +0,0 @@ -/* - Copyright (c) 2015-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 "SFMethodInterceptor.h" -#import -#import - -/** This static dictionary contains a map of to . - In other words, it helps get the interceptor instance for a given - pair of class and selector. The class is the class to intercept - an the selector is the selector to intercept - */ -static NSMutableDictionary *InterceptorsForClassAndSelector = nil; - -/** This method returns a key given a class and a selector - */ -static NSString * interceptorKey(Class clazz, SEL selector, BOOL isInstanceMethod) { - return [NSString stringWithFormat:@"%@:%@:%d", NSStringFromClass(clazz), NSStringFromSelector(selector), isInstanceMethod]; -} - -static NSString * const kSFSDKInstrumentationForwardMethodPrefix = @"__method_forwarded_"; -static NSString * const kSFSDKInstrumentationForwardBlockPrefix = @"__method_forwarded_block_"; - -@implementation SFSDKInstrumentationPostExecutionData - -- (NSString *)description { - return [NSString stringWithFormat:@"<%@:%p selectorName: %@, isInstanceMethod: %d, executionStartDate: %@, executionEndDate: %@, executionTime: %f>", [self class], self, self.selectorName, self.isInstanceMethod, self.executionStartDate, self.executionEndDate, self.executionTime]; -} - -@end - -@interface SFMethodInterceptor () - -/** The instance or class of the intercepted object. - */ -@property (nonatomic, weak) id interceptedObject; - -/** Returns a selector who's method implementation contains - the original method that was intercepted. - This selector has been renamed to ensure it doesn't collide - with the original selector or any other existing method - */ -@property (nonatomic, readonly) SEL originalMethodRenamedSelector; -@property (nonatomic, readonly) SEL originalMethodRenamedSelectorForBlock; - -@property (nonatomic, strong) NSMethodSignature *interceptedMethodSignature; - -@end - -@implementation SFMethodInterceptor - -+ (void)initialize { - if (self == [SFMethodInterceptor class] && nil == InterceptorsForClassAndSelector) { - InterceptorsForClassAndSelector = [NSMutableDictionary dictionary]; - } -} - -- (instancetype)init { - self = [super init]; - if (self) { - _enabled = NO; - } - return self; -} - -- (void)dealloc { - self.enabled = NO; -} - -- (BOOL)isEqual:(id)object { - if (![object isKindOfClass:[self class]]) { - return NO; - } - - SFMethodInterceptor *otherObj = (SFMethodInterceptor *)object; - return ((otherObj.classToIntercept == self.classToIntercept) - && (otherObj.selectorToIntercept == self.selectorToIntercept) - && (otherObj.instanceMethod == self.instanceMethod)); -} - -- (NSUInteger)hash { - NSString *hashString = [NSString stringWithFormat:@"%@_%@_%d", NSStringFromClass(self.classToIntercept), NSStringFromSelector(self.selectorToIntercept), self.instanceMethod]; - return [hashString hash]; -} - -- (SEL)originalMethodRenamedSelector { - // Rename the original selector by inserting a string that ensure it's unique - NSMutableString *name = [[NSMutableString alloc] initWithCString:sel_getName(self.selectorToIntercept) encoding:NSASCIIStringEncoding]; - [name insertString:kSFSDKInstrumentationForwardMethodPrefix atIndex:0]; - - // use sel_registerName() and not @selector to avoid warning - SEL sel = sel_registerName([name cStringUsingEncoding:NSASCIIStringEncoding]); - return sel; -} - -- (SEL)originalMethodRenamedSelectorForBlock { - // Rename the original selector by inserting a string that ensure it's unique - NSMutableString *name = [[NSMutableString alloc] initWithCString:sel_getName(self.selectorToIntercept) encoding:NSASCIIStringEncoding]; - [name insertString:kSFSDKInstrumentationForwardBlockPrefix atIndex:0]; - - // use sel_registerName() and not @selector to avoid warning - SEL sel = sel_registerName([name cStringUsingEncoding:NSASCIIStringEncoding]); - return sel; -} - -#pragma mark - Forwarding & Swizzling - -- (id)forwardingTargetForSelector:(SEL)aSelector { - // Here `self` is expected to refer to the class instance that's being intercepted - if ([self isKindOfClass:[SFMethodInterceptor class]]) { - // If not, then it means some unknown method is called on the SFMethodInterceptor class - // instance which is left untouched. - return [super forwardingTargetForSelector:aSelector]; - } else { - // Let's find out which interceptor instance is managing - // this selector and class - BOOL isInstanceSelector = !(class_isMetaClass(object_getClass(self))); - SFMethodInterceptor *interceptor = InterceptorsForClassAndSelector[interceptorKey([self class], aSelector, isInstanceSelector)]; - if (interceptor) { - interceptor.interceptedObject = self; - return interceptor; - } else { - return [super forwardingTargetForSelector:aSelector]; - } - } -} - -/** This method is invoked on the SFMethodInterceptor class when - a unknown selector is invoked on that class. Normally, it's - the selector that's being intercepted that's provided here. - We return the intercepted method signature that was captured - when the interceptor was created so the Objective-C forwarding - machinery can correctly create the invocation. - */ -- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { - return self.interceptedMethodSignature; -} - -/** After `methodSignatureForSelector` has been invoked, this - methid is invoked with the invocation that contains the description - of the message that was intercepted. - This is here that we intercept the message, call back any registered - callback blocks and then invoke the original method code (or skip it). - */ -- (void)forwardInvocation:(NSInvocation *)anInvocation { - if ([self isKindOfClass:[SFMethodInterceptor class]]) { - anInvocation.target = self.interceptedObject; - anInvocation.selector = self.originalMethodRenamedSelector; - - [self invokeCallbacks:anInvocation]; - } else { - [super forwardInvocation:anInvocation]; - } -} - -- (void)invokeCallbacks:(NSInvocation*)anInvocation { - if (self.targetBeforeBlock) { - self.targetBeforeBlock(anInvocation); - } - NSDate *startTime = [NSDate date]; - if (self.targetReplaceBlock) { - self.targetReplaceBlock(anInvocation); - } else { - [self invokeOriginal:anInvocation]; - } - NSDate *endTime = [NSDate date]; - if (self.targetAfterBlock) { - SFSDKInstrumentationPostExecutionData *data = [[SFSDKInstrumentationPostExecutionData alloc] init]; - Class targetClass = object_getClass(anInvocation.target); - data.className = NSStringFromClass(targetClass); - data.selectorName = [NSStringFromSelector(anInvocation.selector) substringFromIndex:kSFSDKInstrumentationForwardMethodPrefix.length]; - data.isInstanceMethod = !(class_isMetaClass(targetClass)); - data.executionStartDate = startTime; - data.executionEndDate = endTime; - data.executionTime = [endTime timeIntervalSinceDate:startTime]; - self.targetAfterBlock(anInvocation, data); - } -} - -- (void)invokeOriginal:(NSInvocation*)anInvocation { - anInvocation.selector = self.originalMethodRenamedSelector; - [anInvocation invokeWithTarget:self.interceptedObject]; -} - -- (void)swizzle { - if (_enabled) { - return; - } - if (self.instanceMethod) { - Method originalMethod = class_getInstanceMethod(self.classToIntercept, self.selectorToIntercept); - const char *methodTypes = method_getTypeEncoding(originalMethod); - - @synchronized (InterceptorsForClassAndSelector) { - InterceptorsForClassAndSelector[interceptorKey(self.classToIntercept, self.selectorToIntercept, self.instanceMethod)] = self; - } - - // forward method - IMP originalMethodIMP = method_setImplementation(originalMethod, (IMP)_objc_msgForward); - NSAssert(originalMethodIMP, @"Original method implementation must be found"); - - SEL forwardingSelector = @selector(forwardingTargetForSelector:); - Method forwardingMethod = class_getInstanceMethod([self class], forwardingSelector); - IMP forwardingMethodIMP = method_getImplementation(forwardingMethod); - const char *forwardingMethodTypes = method_getTypeEncoding(forwardingMethod); - class_replaceMethod(self.classToIntercept, forwardingSelector, forwardingMethodIMP, forwardingMethodTypes); - - self.interceptedMethodSignature = [self.classToIntercept instanceMethodSignatureForSelector:self.selectorToIntercept]; - - class_replaceMethod(self.classToIntercept, self.originalMethodRenamedSelector, originalMethodIMP, methodTypes); - } else { - // Note: class method must be added to the class's metaclass - Class originalMetaClass = objc_getMetaClass(object_getClassName(self.classToIntercept)); - - Method originalMethod = class_getClassMethod(originalMetaClass, self.selectorToIntercept); - const char *methodTypes = method_getTypeEncoding(originalMethod); - - @synchronized (InterceptorsForClassAndSelector) { - InterceptorsForClassAndSelector[interceptorKey(self.classToIntercept, self.selectorToIntercept, self.instanceMethod)] = self; - } - - // forward method - IMP originalMethodIMP = method_setImplementation(originalMethod, (IMP)_objc_msgForward); - NSAssert(originalMethodIMP, @"Original method implementation must be found"); - - SEL forwardingSelector = @selector(forwardingTargetForSelector:); - Method forwardingMethod = class_getInstanceMethod([self class], forwardingSelector); - IMP forwardingMethodIMP = method_getImplementation(forwardingMethod); - const char *forwardingMethodTypes = method_getTypeEncoding(forwardingMethod); - class_replaceMethod(originalMetaClass, forwardingSelector, forwardingMethodIMP, forwardingMethodTypes); - - self.interceptedMethodSignature = [self.classToIntercept methodSignatureForSelector:self.selectorToIntercept]; - - class_replaceMethod(originalMetaClass, self.originalMethodRenamedSelector, originalMethodIMP, methodTypes); - } - [SFSDKCoreLogger d:[self class] format:@"%@ is ENABLED", self]; -} - -- (void)unswizzle { - if (!_enabled) { - return; - } - if (self.instanceMethod) { - Method targetMethod = class_getInstanceMethod(self.classToIntercept, self.selectorToIntercept); - Method originalMethod = class_getInstanceMethod(self.classToIntercept, self.originalMethodRenamedSelector); - method_exchangeImplementations(originalMethod, targetMethod); - } else { - Method targetMethod = class_getClassMethod(self.classToIntercept, self.selectorToIntercept); - Method originalMethod = class_getClassMethod(self.classToIntercept, self.originalMethodRenamedSelector); - method_exchangeImplementations(originalMethod, targetMethod); - } - @synchronized (InterceptorsForClassAndSelector) { - [InterceptorsForClassAndSelector removeObjectForKey:interceptorKey(self.classToIntercept, self.selectorToIntercept, self.instanceMethod)]; - } - [SFSDKCoreLogger d:[self class] format:@"%@ is DISABLED", self]; -} - -- (void)setEnabled:(BOOL)enabled { - if (_enabled != enabled) { - [self willChangeValueForKey:@"enabled"]; - if (enabled) { - [self swizzle]; - } else { - [self unswizzle]; - } - _enabled = enabled; - [self didChangeValueForKey:@"enabled"]; - } -} - -- (NSString*)description { - return [NSString stringWithFormat:@"<%@: %p, %@::%@>", NSStringFromClass([self class]), self, NSStringFromClass(self.classToIntercept), NSStringFromSelector(self.selectorToIntercept)]; -} - -@end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFRestAPI+Instrumentation.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFRestAPI+Instrumentation.h deleted file mode 100644 index 1093fb4883..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFRestAPI+Instrumentation.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - SFRestAPI+Instrumentation.h - SalesforceSDKCore - Created by Raj Rao on 3/7/19. - - Copyright (c) 2019-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 - -NS_ASSUME_NONNULL_BEGIN - -@interface SFRestAPI(Instrumentation) - -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFRestAPI+Instrumentation.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFRestAPI+Instrumentation.m deleted file mode 100644 index e91f73906e..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFRestAPI+Instrumentation.m +++ /dev/null @@ -1,122 +0,0 @@ -/* - SFRestAPI+Instrumentation.m - SalesforceSDKCore - Created by Raj Rao on 3/7/19. - - Copyright (c) 2019-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 "SFRestAPI+Instrumentation.h" -#import "SFRestRequest+Internal.h" -#import "SalesforceSDKConstants.h" -#import "SFSDKInstrumentationHelper.h" -#import -#import -#import -#import "SFSDKCoreLogger.h" - -@interface SFRestDelegateWrapperWithInstrumentation: NSObject - -- (instancetype)initWithRequestDelegate:(id)requestDelegate signpost:(os_signpost_id_t)signpostId logger:(os_log_t)logger; - -@property (weak, nonatomic, readonly) id requestDelegate; -@property (nonatomic, readonly) os_signpost_id_t signpostId; -@property (nonatomic, readonly) os_log_t logger; - -+ (id)factoryWith:requestDelegate signpost:(os_signpost_id_t)signpostId logger:(os_log_t)logger; - -@end - -@implementation SFRestDelegateWrapperWithInstrumentation - -- (instancetype)initWithRequestDelegate:(id)requestDelegate signpost:(os_signpost_id_t)signpostId logger:(os_log_t)logger { - if (self = [super init]) { - _requestDelegate = requestDelegate; - _signpostId = signpostId; - _logger = logger; - } - return self; -} - -- (void)request:(SFRestRequest *)request didSucceed:(id)dataResponse rawResponse:(NSURLResponse *)rawResponse { - sf_os_signpost_interval_end(self.logger, self.signpostId, "Send", "requestDidSucceed %ld %{public}@", (long)request.method, request.path); - if ([self.requestDelegate respondsToSelector:@selector(request:didSucceed:rawResponse:)]) { - [self.requestDelegate request:request didSucceed:dataResponse rawResponse:rawResponse]; - } - request.instrumentationDelegateInternal = nil; -} - -- (void)request:(SFRestRequest *)request didFail:(id)dataResponse rawResponse:(NSURLResponse *)rawResponse error:(NSError *)error { - sf_os_signpost_interval_end(self.logger, self.signpostId, "Send", "requestDidFail %ld %{public}@", (long)request.method, request.path); - if ([self.requestDelegate respondsToSelector:@selector(request:didFail:rawResponse:error:)]) { - [self.requestDelegate request:request didFail:dataResponse rawResponse:rawResponse error:error]; - } - request.instrumentationDelegateInternal = nil; -} - -+ (id)factoryWith:requestDelegate signpost:(os_signpost_id_t)signpostId logger:(os_log_t)logger { - return (id) [[SFRestDelegateWrapperWithInstrumentation alloc] initWithRequestDelegate:requestDelegate signpost:signpostId logger:logger]; -} - -@end - -@implementation SFRestAPI(Instrumentation) - -+ (os_log_t)oslog { - static os_log_t _logger; - static dispatch_once_t pred; - dispatch_once(&pred, ^{ - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - _logger = os_log_create([appName cStringUsingEncoding:NSUTF8StringEncoding], [@"SFRestAPI" cStringUsingEncoding:NSUTF8StringEncoding]); - }); - return _logger; -} - -+ (void)load { - if ([SFSDKInstrumentationHelper isEnabled] && (self == SFRestAPI.self)) { - [self enableInstrumentation]; - } -} - -+ (void)enableInstrumentation { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - Class class = [self class]; - SEL originalSelector = @selector(send:requestDelegate:); - SEL swizzledSelector = @selector(instrumentation_send:requestDelegate:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - }); -} - -- (void)instrumentation_send:(SFRestRequest *)request requestDelegate:(id)requestDelegate { - - // Begin an os_signpost_interval. - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "Send", "Method:%ld path:%{public}@", (long)request.method, request.path); - id delegateWrapper = [SFRestDelegateWrapperWithInstrumentation factoryWith:requestDelegate signpost:sid logger:logger]; - request.instrumentationDelegateInternal = delegateWrapper; - return [self instrumentation_send:request requestDelegate:delegateWrapper]; -} - -@end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFSDKInstrumentationHelper.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFSDKInstrumentationHelper.h deleted file mode 100644 index 9573a1c651..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFSDKInstrumentationHelper.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - SFSDKInstrumentationHelper.h - SalesforceSDKCore - Created by Raj Rao on 3/7/19. - - Copyright (c) 2019-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 - -NS_ASSUME_NONNULL_BEGIN - -NS_SWIFT_NAME(SalesforceInstrumentationHelper) -/// @deprecated Signpost logging is deprecated and this helper will be removed in version 14.0. -SFSDK_DEPRECATED(13.1, 14.0, "Signpost logging is deprecated and will be removed."); -@interface SFSDKInstrumentationHelper : NSObject -@property (class,nonatomic,readonly) BOOL isEnabled; -+ (void)swizzleMethod:(SEL)originalSelector with:(SEL)swizzledSelector forClass:(Class)clazz isInstanceMethod:(BOOL)isInstanceMethod; -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFSDKInstrumentationHelper.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFSDKInstrumentationHelper.m deleted file mode 100644 index f00d5e05a9..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFSDKInstrumentationHelper.m +++ /dev/null @@ -1,74 +0,0 @@ -/* - SFSDKInstrumentationHelper.m - SalesforceSDKCore - Created by Raj Rao on 3/7/19. - - Copyright (c) 2019-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 "SFSDKInstrumentationHelper.h" -#import "SFInstrumentation.h" -#import - -@interface SFSDKInstrumentationHelper () -@end - -@implementation SFSDKInstrumentationHelper - -+ (BOOL)isEnabled { - #ifdef SIGNPOST_ENABLED - return YES; - #endif - return NO; -} - -+ (void)swizzleMethod:(SEL)originalSelector with:(SEL)swizzledSelector forClass:(Class)clazz isInstanceMethod:(BOOL)isInstanceMethod { - - Method originalMethod; - Method swizzledMethod; - - if (isInstanceMethod) { - originalMethod = class_getInstanceMethod(clazz, originalSelector); - swizzledMethod = class_getInstanceMethod(clazz, swizzledSelector); - } else { - originalMethod = class_getClassMethod(clazz, originalSelector); - swizzledMethod = class_getClassMethod(clazz, swizzledSelector); - } - - BOOL didAddMethod = - class_addMethod(clazz, - originalSelector, - method_getImplementation(swizzledMethod), - method_getTypeEncoding(swizzledMethod)); - - if (didAddMethod) { - class_replaceMethod(clazz, - swizzledSelector, - method_getImplementation(originalMethod), - method_getTypeEncoding(originalMethod)); - } else { - method_exchangeImplementations(originalMethod, swizzledMethod); - } -} - -@end - diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFUserAccountManager+Instrumentation.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFUserAccountManager+Instrumentation.h deleted file mode 100644 index 86e7e80549..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFUserAccountManager+Instrumentation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - SFUserAccountManager+Instrumentation.h - SalesforceSDKCore - Created by Raj Rao on 3/7/19. - - Copyright (c) 2019-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 - -@interface SFUserAccountManager (Instrumentation) - -@end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFUserAccountManager+Instrumentation.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFUserAccountManager+Instrumentation.m deleted file mode 100644 index 159fd9cf8e..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Instrumentation/SFUserAccountManager+Instrumentation.m +++ /dev/null @@ -1,169 +0,0 @@ -/* - SFUserAccountManager+Instrumentation.m - SalesforceSDKCore - Created by Raj Rao on 3/7/19. - - Copyright (c) 2019-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 "SFUserAccountManager+Instrumentation.h" -#import "SFSDKInstrumentationHelper.h" -#import -#import -#import -#import "SFSDKCoreLogger.h" - -@implementation SFUserAccountManager(Instrumentation) - -+ (os_log_t)oslog { - static os_log_t _logger; - static dispatch_once_t pred; - dispatch_once(&pred, ^{ - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - _logger = os_log_create([appName cStringUsingEncoding:NSUTF8StringEncoding], [@"SFUserAccountManager" cStringUsingEncoding:NSUTF8StringEncoding]); - }); - return _logger; -} - - -+ (void)load{ - - if ([SFSDKInstrumentationHelper isEnabled] && (self == SFUserAccountManager.self)) { - [self enableInstrumentation]; - } -} - - -+ (void)enableInstrumentation{ - static dispatch_once_t once; - dispatch_once(&once, ^{ - [SFSDKCoreLogger d:[self class] format:@"Swizzled :: SFUserAccountManager"]; - - SEL originalSelector = @selector(loginWithCompletion:failure:); - SEL swizzledSelector = @selector(instr_loginWithCompletion:failure:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:self isInstanceMethod:YES]; - - originalSelector = @selector(refreshCredentials:completion:failure:); - swizzledSelector = @selector(instr_refreshCredentials:completion:failure:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:self isInstanceMethod:YES]; - - originalSelector = @selector(loginWithJwtToken:completion:failure:); - swizzledSelector = @selector(instr_loginWithJwtToken:completion:failure:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:self isInstanceMethod:YES]; - - originalSelector = @selector(logout); - swizzledSelector = @selector(instr_logout); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:self isInstanceMethod:YES]; - - originalSelector = @selector(logoutAllUsers); - swizzledSelector = @selector(instr_logoutAllUsers); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:self isInstanceMethod:YES]; - - originalSelector = @selector(logoutUser:); - swizzledSelector = @selector(instr_logoutUser:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:self isInstanceMethod:YES]; - }); -} - -- (BOOL)instr_loginWithCompletion:(nullable SFUserAccountManagerSuccessCallbackBlock)completionBlock - failure:(nullable SFUserAccountManagerFailureCallbackBlock)failureBlock { - // Begin an os_signpost_interval. - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "Salesforce Login", "Begin"); - - return [self instr_loginWithCompletion:^(SFOAuthInfo *authInfo, SFUserAccount *account) { - sf_os_signpost_interval_end(logger, sid, "Salesforce Login", "End - Success"); - if (completionBlock) completionBlock(authInfo,account); - } failure:^(SFOAuthInfo * authInfo, NSError * error) { - sf_os_signpost_interval_end(logger, sid, "Salesforce Login", "End - Failure"); - if (failureBlock) failureBlock(authInfo,error); - }]; - -} - - -- (BOOL)instr_refreshCredentials:(nonnull SFOAuthCredentials *)credentials - completion:(nullable SFUserAccountManagerSuccessCallbackBlock)completionBlock - failure:(nullable SFUserAccountManagerFailureCallbackBlock)failureBlock { - // Begin an os_signpost_interval. - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "Salesforce Refresh", "Begin"); - - return [self instr_refreshCredentials:credentials completion:^(SFOAuthInfo *authInfo, SFUserAccount *account) { - sf_os_signpost_interval_end(logger, sid, "Salesforce Refresh", "End - Success"); - if (completionBlock) completionBlock(authInfo,account); - } failure:^(SFOAuthInfo * authInfo, NSError * error) { - sf_os_signpost_interval_end(logger, sid, "Salesforce Refresh", "End - Failure"); - if (failureBlock) failureBlock(authInfo,error); - }]; -} - -- (BOOL)instr_loginWithJwtToken:(NSString *)jwtToken - completion:(nullable SFUserAccountManagerSuccessCallbackBlock)completionBlock - failure:(nullable SFUserAccountManagerFailureCallbackBlock)failureBlock { - // Begin an os_signpost_interval. - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "Salesforce Login JWT", "Begin"); - - return [self instr_loginWithJwtToken:jwtToken completion:^(SFOAuthInfo *authInfo, SFUserAccount *account) { - sf_os_signpost_interval_end(logger, sid, "Salesforce Login JWT", "Did Login user %{public}@",account.idData.username); - if (completionBlock) completionBlock(authInfo,account); - } failure:^(SFOAuthInfo * authInfo, NSError * error) { - sf_os_signpost_interval_end(logger, sid, "Salesforce Login JWT", "Login - Failure"); - if (failureBlock) failureBlock(authInfo,error); - }]; -} - -- (void)instr_logout { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - NSString *currentUsername = self.currentUser.idData.username; - sf_os_signpost_interval_begin(logger, sid, "Salesforce Logout", "Will Logout current user %{public}@",currentUsername); - [self instr_logout]; - sf_os_signpost_interval_end(logger, sid, "Salesforce Logout", "Did Logout current user %{public}@",currentUsername); - return; -} - -- (void)instr_logoutUser:(SFUserAccount *)user { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - NSString *username = user.idData.username; - sf_os_signpost_interval_begin(logger, sid, "Salesforce Logout User","Will Logout user %{public}@",username); - [self instr_logoutUser:user]; - sf_os_signpost_interval_end(logger, sid, "Salesforce Logout User", "Did Logout user %{public}@",username); - return; -} - -- (void)instr_logoutAllUsers { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "Salesforce Logout All Users", "Begin"); - [self instr_logoutAllUsers]; - sf_os_signpost_interval_end(logger, sid, "Salesforce Logout All Users", "End - Success"); - -} - -@end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h index 4860f8a25e..078d002ac0 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h @@ -57,6 +57,14 @@ NS_SWIFT_NAME(SalesforceLoginViewControllerDelegate) - (void)loginViewControllerDidChangeLoginOptions:(nonnull SFLoginViewController *)loginViewController; +/** + * Notifies the delegate that the user selected "Login for Admin" from the settings menu. + * This forces browser-based (advanced) authentication via ASWebAuthenticationSession, + * regardless of org configuration, to support phishing-resistant MFA. + * @param loginViewController The instance sending this message. + */ +- (void)loginViewControllerDidSelectLoginForAdmin:(nonnull SFLoginViewController *)loginViewController; + @end /** The Salesforce login screen view. diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m index 21f08d4140..774b9810ae 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m @@ -325,7 +325,17 @@ - (UIBarButtonItem *)createSettingsButton { [self presentViewController:configPicker animated:YES completion:nil]; }]]; } - + + // Login for Admin - forces browser-based (advanced) authentication to support phishing-resistant MFA. + [menuActions addObject:[UIAction actionWithTitle:[SFSDKResourceUtils localizedString:@"LOGIN_FOR_ADMIN"] + image:nil + identifier:nil + handler:^(__kindof UIAction* _Nonnull action) { + if ([self.delegate respondsToSelector:@selector(loginViewControllerDidSelectLoginForAdmin:)]) { + [self.delegate loginViewControllerDidSelectLoginForAdmin:self]; + } + }]]; + UIMenu *menu = [UIMenu menuWithTitle:@"" // No title children:menuActions]; UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithImage:image menu:menu]; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.h index 883ad1ad91..7de4875cec 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.h @@ -260,13 +260,6 @@ typedef void (^SFOAuthBrowserFlowCallbackBlock)(BOOL); */ @property (nonatomic, readonly, null_unspecified) ASWebAuthenticationSession *asWebAuthenticationSession; -/** - The user agent string that will be used for authentication. While this property will persist throughout - the lifetime of the coordinator object, the user agent configured for the system will be reset back to - its original value in between authentication requests. - */ -@property (nonatomic, copy) NSString *userAgentForAuth SFSDK_DEPRECATED(13.2, 14.0, "Not used, will be removed."); - /** An array of additional keys (NSString) to parse during OAuth */ diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m index 9019222aa7..83b80d3cbf 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m @@ -78,7 +78,6 @@ @implementation SFOAuthCoordinator @synthesize scopes = _scopes; @synthesize codeVerifier = _codeVerifier; @synthesize authInfo = _authInfo; -@synthesize userAgentForAuth = _userAgentForAuth; @synthesize origWebUserAgent = _origWebUserAgent; @@ -145,6 +144,8 @@ - (void)authenticate { self.authenticating = YES; if (self.credentials.refreshToken) { self.authInfo = [[SFOAuthInfo alloc] initWithAuthType:SFOAuthTypeRefresh]; + } else if (self.useBrowserAuth) { + self.authInfo = [[SFOAuthInfo alloc] initWithAuthType:SFOAuthTypeAdvancedBrowser]; } else if ([[SalesforceSDKManager sharedManager] useWebServerAuthentication]) { self.authInfo = [[SFOAuthInfo alloc] initWithAuthType:SFOAuthTypeWebServer]; } else { @@ -619,12 +620,6 @@ - (void)beginTokenEndpointFlow { request.refreshToken = self.credentials.refreshToken; request.redirectURI = self.credentials.redirectUri; request.serverURL = [self.credentials overrideDomainIfNeeded]; - - // TODO: Remove in Mobile SDK 14.0 - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - request.userAgentForAuth = self.userAgentForAuth; - #pragma clang diagnostic pop __weak typeof (self) weakSelf = self; if (self.approvalCode) { @@ -777,7 +772,7 @@ - (void)handleUserAgentResponse:(NSURL *)requestUrl { - (NSString *)generateApprovalUrlString { return [self approvalURLForEndpoint:[self brandedAuthorizeURL] credentials:self.credentials - webServerFlow:[[SalesforceSDKManager sharedManager] useWebServerAuthentication] + webServerFlow:(self.useBrowserAuth || [[SalesforceSDKManager sharedManager] useWebServerAuthentication]) protocol:nil domain:nil codeChallenge:nil]; @@ -893,7 +888,7 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati // If a front door bridge URL override is present, use its code verifier to choose between user agent or web server authentication. if (self.frontdoorBridgeLoginOverride.frontdoorBridgeUrl // Check if an override is provided ? self.frontdoorBridgeLoginOverride.codeVerifier != nil // If yes, only proceed if it's a web server flow as indicated by a code verifier. - : [[SalesforceSDKManager sharedManager] useWebServerAuthentication] // If there's no override use the default SDK setting. + : (self.useBrowserAuth || [[SalesforceSDKManager sharedManager] useWebServerAuthentication]) // If there's no override use browser auth or the default SDK setting. ) { [self handleWebServerResponse:url]; // Web server flow/URLs with query string parameters. diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthRequest.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthRequest.h index e886007652..adb4c12849 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthRequest.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthRequest.h @@ -32,6 +32,11 @@ NS_ASSUME_NONNULL_BEGIN @interface SFSDKAuthRequest : NSObject @property (nonatomic, assign) BOOL useBrowserAuth; + +/// Indicates that browser auth was initiated by the "Login for Admin" action. +/// When YES, cancelling the browser session returns to the WebView login instead of showing the server picker. +@property (nonatomic, assign) BOOL loginAsAdmin; + @property (nonatomic, strong) NSArray *additionalOAuthParameterKeys; @property (nonatomic, strong) NSDictionary * additionalTokenRefreshParams; @property (nonatomic, copy) NSString *loginHost; @@ -43,7 +48,6 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic,strong) SFSDKLoginViewControllerConfig *loginViewControllerConfig; @property (nullable, nonatomic, strong) UIScene *scene; @property (nonatomic, copy) NSString *jwtToken; -@property (nonatomic, copy, nullable) NSString *userAgentForAuth; //IDP flow related properties (SPApp related properties) @property (nonatomic, readonly, assign) BOOL idpEnabled; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthSession.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthSession.m index 9d7ab24b20..8fca3062e6 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthSession.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthSession.m @@ -60,13 +60,7 @@ -(void)initCoordinator { self.oauthCoordinator.additionalTokenRefreshParams = self.oauthRequest.additionalTokenRefreshParams; self.oauthCoordinator.scopes = self.oauthRequest.scopes; self.oauthCoordinator.brandLoginPath = self.oauthRequest.brandLoginPath; - self.oauthCoordinator.useBrowserAuth = self.oauthRequest.useBrowserAuth; - - // TODO: Remove in Mobile SDK 14.0 - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - self.oauthCoordinator.userAgentForAuth = self.oauthRequest.userAgentForAuth; - #pragma clang diagnostic pop + self.oauthCoordinator.useBrowserAuth = self.oauthRequest.useBrowserAuth || self.oauthRequest.loginAsAdmin; if (_spAppCredentials && _spAppCredentials.domain) { self.oauthCoordinator.credentials.domain = _spAppCredentials.domain; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Security/ScreenLock/ScreenLockUIView.swift b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Security/ScreenLock/ScreenLockUIView.swift index 1c84b53dce..82e4f5d5fb 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Security/ScreenLock/ScreenLockUIView.swift +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Security/ScreenLock/ScreenLockUIView.swift @@ -126,8 +126,6 @@ private func logout() { } } -struct ScreenLockUIView_Previews: PreviewProvider { - static var previews: some View { - ScreenLockUIView() - } +#Preview { + ScreenLockUIView() } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Storage/KeyValueEncryptedFileStoreInspector.swift b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Storage/KeyValueEncryptedFileStoreInspector.swift index 7aa87bb206..769634b7c1 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Storage/KeyValueEncryptedFileStoreInspector.swift +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Storage/KeyValueEncryptedFileStoreInspector.swift @@ -161,9 +161,7 @@ struct KeyValuePair: Hashable { var value: String } -struct KeyValueEncryptedFileStoreInpector_Previews: PreviewProvider { - static var previews: some View { - KeyValueEncryptedFileStoreInspector() - } +#Preview { + KeyValueEncryptedFileStoreInspector() } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKAsyncProcessListener.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKAsyncProcessListener.h deleted file mode 100644 index cdaa296def..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKAsyncProcessListener.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (c) 2015-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 -#import - -NS_ASSUME_NONNULL_BEGIN - -SFSDK_DEPRECATED(13.2, 14.0, "No longer used, will be removed") -@interface SFSDKAsyncProcessListener : NSObject - -/** - Designated initializer. Initialize the process listener with an expected status and a block that - will return status updates when called. - @param expectedStatus The expected return status upon completion. - @param actualStatusBlock The block that will return the actual status when called. - @param timeout The amount of time before the asynchronous process is considered to time out. - */ -- (id)initWithExpectedStatus:(id)expectedStatus actualStatusBlock:(id (^)(void))actualStatusBlock timeout:(NSTimeInterval)timeout; - -/** - Waits for the asynchronous process to complete. - @return The actual status at the time the process completes, or times out. - */ -- (id)waitForCompletion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKAsyncProcessListener.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKAsyncProcessListener.m deleted file mode 100644 index f25185d0ab..0000000000 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/SFSDKAsyncProcessListener.m +++ /dev/null @@ -1,71 +0,0 @@ -/* - Copyright (c) 2015-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 "SFSDKAsyncProcessListener.h" - -static NSTimeInterval const kDefaultWaitTimeout = 5.0; - -@interface SFSDKAsyncProcessListener () - -@property (nonatomic, strong) id exectedStatus; -@property (nonatomic, copy) id (^actualStatusBlock)(void); -@property (nonatomic, assign) NSTimeInterval timeout; - -@end - -@implementation SFSDKAsyncProcessListener - -@synthesize exectedStatus = _exectedStatus; -@synthesize actualStatusBlock = _actualStatusBlock; -@synthesize timeout = _timeout; - -- (id)initWithExpectedStatus:(id)expectedStatus actualStatusBlock:(id (^)(void))actualStatusBlock timeout:(NSTimeInterval)timeout { - self = [super init]; - if (self) { - NSAssert(expectedStatus != nil, @"expectedStatus value should be non-nil"); - NSAssert(actualStatusBlock != NULL, @"Must specify a block to return the actual status."); - self.exectedStatus = expectedStatus; - self.actualStatusBlock = actualStatusBlock; - self.timeout = (timeout > 0 ? timeout : kDefaultWaitTimeout); - } - return self; -} - -- (id)waitForCompletion { - NSDate *startTime = [NSDate date]; - id actualStatus = self.actualStatusBlock(); - while (![self.exectedStatus isEqual:actualStatus]) { - NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:startTime]; - if (elapsed > self.timeout) { - [SFSDKCoreLogger d:[self class] format:@"%@|%@: Async process took too long (> %f secs) to complete.", NSStringFromClass([self class]), NSStringFromSelector(_cmd), elapsed]; - return actualStatus; - } - [SFSDKCoreLogger d:[self class] format:@"%@|%@: Expected %@, got %@. ## sleeping...", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.exectedStatus, actualStatus]; - [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - actualStatus = self.actualStatusBlock(); - } - return actualStatus; -} - -@end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.h index b22720b347..b328e839a0 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.h @@ -31,6 +31,7 @@ #import @class SFSDKSPConfig; +@class SFLoginViewController; NS_ASSUME_NONNULL_BEGIN @@ -625,6 +626,34 @@ Use this method to stop/clear any authentication which is has already been start statusUpdate:(void(^)(SFSPLoginStatus))statusBlock failure:(void(^)(SFSPLoginError))failureBlock; +/** + Triggers the "Login for Admin" flow for the active login session associated with the given + login view controller. Forces browser-based (advanced) authentication via ASWebAuthenticationSession, + regardless of org configuration, to support phishing-resistant MFA. + + This performs the same action as selecting "Login for Admin" from the login screen's settings + menu. Apps that hide the settings menu (e.g. by setting `showSettingsIcon = NO`) can call this + to expose the feature from their own UI. + + To obtain a reference to the currently presented `SFLoginViewController`, either: + + 1. Capture it from `SFSDKLoginViewControllerConfig.loginViewControllerCreationBlock`, which + the SDK invokes each time it constructs the login view: + + UserAccountManager.shared.loginViewControllerConfig.loginViewControllerCreationBlock = { [weak self] in + let vc = SalesforceLoginViewController() + self?.currentLoginVC = vc // retain weakly for later + return vc + } + + 2. Walk the key window's view hierarchy and locate the `SFLoginViewController` presented + inside the SDK's navigation controller. + + @param loginViewController The login view controller whose scene's active auth session should + switch to "Login for Admin". Its window's scene is used to locate the session. + */ +- (void)loginViewControllerDidSelectLoginForAdmin:(SFLoginViewController *)loginViewController NS_SWIFT_NAME(loginViewControllerDidSelectLoginForAdmin(_:)) SFSDK_DEPRECATED(13.2.1, 14.0, "Will be removed in 14.0 when a permanent solution is provided."); + @end NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m index b27048c17c..885dce308a 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m @@ -1030,14 +1030,22 @@ - (void)oauthCoordinatorDidCancelBrowserAuthentication:(SFOAuthCoordinator *)coo }); return; } - + + // When "Login for Admin" initiated the browser auth, clear the flag and + // restart the WebView login flow instead of showing the server picker. + if (coordinator.authSession.oauthRequest.loginAsAdmin) { + coordinator.authSession.oauthRequest.loginAsAdmin = NO; + [self restartAuthentication:coordinator.authSession]; + return; + } + if (self.nativeLoginEnabled && self.shouldFallbackToWebAuthentication) { self.shouldFallbackToWebAuthentication = NO; [self stopCurrentAuthentication:nil]; [self loginWithCompletion:^(SFOAuthInfo* authInfo, SFUserAccount* user) { } failure:^(SFOAuthInfo* authInfo, NSError* error) { }]; return; } - + SFOAuthInfo *authInfo = [[SFOAuthInfo alloc] initWithAuthType:SFOAuthTypeAdvancedBrowser]; NSDictionary *userInfo = @{ kSFNotificationUserInfoCredentialsKey: coordinator.credentials, kSFNotificationUserInfoAuthTypeKey: authInfo }; @@ -1114,6 +1122,13 @@ - (void)loginViewControllerDidReload:(SFLoginViewController *)loginViewControlle [self restartAuthenticationForViewController:loginViewController]; } +- (void)loginViewControllerDidSelectLoginForAdmin:(SFLoginViewController *)loginViewController { + NSString *sceneId = loginViewController.view.window.windowScene.session.persistentIdentifier; + SFSDKAuthSession *session = self.authSessions[sceneId]; + session.oauthRequest.loginAsAdmin = YES; + [self restartAuthenticationForViewController:loginViewController]; +} + - (void)loginViewControllerDidChangeLoginOptions:(SFLoginViewController *)loginViewController { [self restartAuthenticationForViewController:loginViewController recreateAuthRequest:YES]; } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.h index 0a6829c9a7..0473d4f80d 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.h @@ -93,7 +93,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SFSDKOAuthTokenEndpointRequest : NSObject @property (nonatomic, copy) NSString *refreshToken; -@property (nonatomic, copy, nullable) NSString *userAgentForAuth; @property (nonatomic, copy) NSString *redirectURI; @property (nonatomic, copy) NSString *clientID; @property (nonatomic, copy, nullable) NSString *approvalCode; @@ -145,15 +144,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)revokeRefreshToken:(SFOAuthCredentials *)credentials reason:(SFLogoutReason)reason; @end -SFSDK_DEPRECATED(13.2, 14.0, "Will be removed.") -@protocol SFSDKOAuthSessionManaging -- (NSURLSession *)createURLSessionWithIdentifier:(nonnull NSString *)identifier; -@end -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -@interface SFSDKOAuth2 : NSObject -#pragma clang diagnostic pop + +@interface SFSDKOAuth2 : NSObject + (NSMutableURLRequest *)requestForRevokeRefreshToken:(SFOAuthCredentials *)credentials reason:(SFLogoutReason)reason; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.m index 8e472f4253..8ef1f50591 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKOAuth2.m @@ -341,13 +341,13 @@ - (void)openIDTokenForRefresh:(SFSDKOAuthTokenEndpointRequest *)endpointReq comp }]; } -#pragma mark - SFSDKOAuthSessionManaging +#pragma mark - private + - (NSURLSession *)createURLSessionWithIdentifier:(NSString *)identifier { SFNetwork *network = [SFNetwork sharedEphemeralInstanceWithIdentifier:identifier]; return network.activeSession; } -#pragma mark - private - (NSMutableURLRequest *)prepareBasicRequest:(SFSDKOAuthTokenEndpointRequest *)endpointReq { NSString *protocolHost = endpointReq.serverURL.absoluteString; NSMutableString *url = [[NSMutableString alloc] initWithFormat:@"%@%@", protocolHost, kSFOAuthEndPointToken]; @@ -359,9 +359,6 @@ - (NSMutableURLRequest *)prepareBasicRequest:(SFSDKOAuthTokenEndpointRequest *)e timeoutInterval:endpointReq.timeout]; [request setHTTPMethod:kHttpMethodPost]; [request setValue:kHttpPostContentType forHTTPHeaderField:kHttpHeaderContentType]; - if (endpointReq.userAgentForAuth != nil) { - [request setValue:endpointReq.userAgentForAuth forHTTPHeaderField:kHttpHeaderUserAgent]; - } [request setHTTPShouldHandleCookies:NO]; return request; } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/SalesforceSDKCore.h b/libs/SalesforceSDKCore/SalesforceSDKCore/SalesforceSDKCore.h index 4d7b09f7c4..e6123a9de3 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/SalesforceSDKCore.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/SalesforceSDKCore.h @@ -40,9 +40,7 @@ #import #import #import -#import #import -#import #import #import #import @@ -115,7 +113,5 @@ #import #import #import -#import #import #import -#import diff --git a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/LoginForAdminTests.swift b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/LoginForAdminTests.swift new file mode 100644 index 0000000000..60497edcae --- /dev/null +++ b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/LoginForAdminTests.swift @@ -0,0 +1,544 @@ +/* + Copyright (c) 2026-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 XCTest +@testable import SalesforceSDKCore + +// MARK: - Login for Admin Tests + +class LoginForAdminTests: XCTestCase { + + private var originalUseWebServerAuth: Bool = true + private var originalUseHybridAuth: Bool = false + + override func setUp() { + super.setUp() + originalUseWebServerAuth = SalesforceManager.shared.useWebServerAuthentication + originalUseHybridAuth = SalesforceManager.shared.useHybridAuthentication + } + + override func tearDown() { + SalesforceManager.shared.useWebServerAuthentication = originalUseWebServerAuth + SalesforceManager.shared.useHybridAuthentication = originalUseHybridAuth + super.tearDown() + } + + // MARK: - SFSDKAuthRequest loginAsAdmin Property + + func testGivenNewAuthRequest_whenCreated_thenLoginAsAdminIsFalse() { + let request = SFSDKAuthRequest() + XCTAssertFalse(request.loginAsAdmin, "loginAsAdmin should default to false") + } + + func testGivenAuthRequest_whenLoginAsAdminSet_thenUseBrowserAuthUnchanged() { + let request = SFSDKAuthRequest() + XCTAssertFalse(request.useBrowserAuth, "useBrowserAuth should default to false") + + request.loginAsAdmin = true + + XCTAssertTrue(request.loginAsAdmin, "loginAsAdmin should be true after setting") + XCTAssertFalse(request.useBrowserAuth, "useBrowserAuth should remain false when loginAsAdmin is set") + } + + // MARK: - SFSDKAuthSession Coordinator Initialization + + func testGivenLoginAsAdmin_whenAuthSessionCreated_thenCoordinatorUsesBrowserAuth() { + let request = makeAuthRequest() + request.loginAsAdmin = true + request.useBrowserAuth = false + + let session = SFSDKAuthSession(request, credentials: nil) + XCTAssertTrue(session.oauthCoordinator.useBrowserAuth, + "Coordinator useBrowserAuth should be true when loginAsAdmin is true") + } + + func testGivenUseBrowserAuthOnly_whenAuthSessionCreated_thenCoordinatorUsesBrowserAuth() { + let request = makeAuthRequest() + request.loginAsAdmin = false + request.useBrowserAuth = true + + let session = SFSDKAuthSession(request, credentials: nil) + XCTAssertTrue(session.oauthCoordinator.useBrowserAuth, + "Coordinator useBrowserAuth should be true when request useBrowserAuth is true") + } + + func testGivenNeitherFlag_whenAuthSessionCreated_thenCoordinatorDoesNotUseBrowserAuth() { + let request = makeAuthRequest() + request.loginAsAdmin = false + request.useBrowserAuth = false + + let session = SFSDKAuthSession(request, credentials: nil) + XCTAssertFalse(session.oauthCoordinator.useBrowserAuth, + "Coordinator useBrowserAuth should be false when both flags are false") + } + + // MARK: - SFOAuthCoordinator Auth Info Type + + func testGivenLoginAsAdmin_whenAuthenticate_thenAuthInfoIsAdvancedBrowser() { + createTestAppIdentity() + + let request = makeAuthRequest() + request.loginAsAdmin = true + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = self + + session.oauthCoordinator.authenticate() + + XCTAssertEqual(session.oauthCoordinator.authInfo.authType, AuthInfo.AuthType.advancedBrowser, + "Auth info type should be advancedBrowser when loginAsAdmin is true") + session.oauthCoordinator.stopAuthentication() + } + + func testGivenWebServerAuth_whenAuthenticate_thenAuthInfoIsWebServer() { + createTestAppIdentity() + SalesforceManager.shared.useWebServerAuthentication = true + + let request = makeAuthRequest() + request.loginAsAdmin = false + request.useBrowserAuth = false + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = self + + session.oauthCoordinator.authenticate() + + XCTAssertEqual(session.oauthCoordinator.authInfo.authType, AuthInfo.AuthType.webServer, + "Auth info type should be webServer when useWebServerAuthentication is true") + session.oauthCoordinator.stopAuthentication() + } + + func testGivenUserAgentAuth_whenAuthenticate_thenAuthInfoIsUserAgent() { + createTestAppIdentity() + SalesforceManager.shared.useWebServerAuthentication = false + + let request = makeAuthRequest() + request.loginAsAdmin = false + request.useBrowserAuth = false + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = self + + session.oauthCoordinator.authenticate() + + XCTAssertEqual(session.oauthCoordinator.authInfo.authType, AuthInfo.AuthType.userAgent, + "Auth info type should be userAgent when both flags are false") + session.oauthCoordinator.stopAuthentication() + } + + // MARK: - Approval URL Web Server Flow + + func testGivenLoginAsAdmin_whenGenerateApprovalUrl_thenUsesWebServerFlow() { + createTestAppIdentity() + SalesforceManager.shared.useWebServerAuthentication = false + + let request = makeAuthRequest() + request.loginAsAdmin = true + + let session = SFSDKAuthSession(request, credentials: nil) + let approvalUrl = session.oauthCoordinator.generateApprovalUrlString() + + XCTAssertTrue(approvalUrl.contains("response_type=code"), + "Approval URL should use response_type=code when loginAsAdmin is true") + XCTAssertFalse(approvalUrl.contains("response_type=token"), + "Approval URL should not use response_type=token when loginAsAdmin is true") + } + + func testGivenNoLoginAsAdmin_whenWebServerAuthDisabled_thenUsesUserAgentFlow() { + createTestAppIdentity() + SalesforceManager.shared.useWebServerAuthentication = false + SalesforceManager.shared.useHybridAuthentication = false + + let request = makeAuthRequest() + request.loginAsAdmin = false + request.useBrowserAuth = false + + let session = SFSDKAuthSession(request, credentials: nil) + let approvalUrl = session.oauthCoordinator.generateApprovalUrlString() + + XCTAssertTrue(approvalUrl.contains("response_type=token"), + "Approval URL should use response_type=token when loginAsAdmin is false and web server auth is disabled") + } + + // MARK: - No Global State Mutation + + func testGivenLoginAsAdmin_whenSet_thenGlobalWebServerAuthUnchanged() { + let originalValue = SalesforceManager.shared.useWebServerAuthentication + + let request = SFSDKAuthRequest() + request.loginAsAdmin = true + + XCTAssertEqual(SalesforceManager.shared.useWebServerAuthentication, originalValue, + "Setting loginAsAdmin should not change the global useWebServerAuthentication") + } + + func testGivenLoginAsAdmin_whenAuthSessionCreated_thenGlobalStateUnchanged() { + SalesforceManager.shared.useWebServerAuthentication = false + + let request = makeAuthRequest() + request.loginAsAdmin = true + + let session = SFSDKAuthSession(request, credentials: nil) + + XCTAssertTrue(session.oauthCoordinator.useBrowserAuth, + "Coordinator should use browser auth") + XCTAssertFalse(SalesforceManager.shared.useWebServerAuthentication, + "Global useWebServerAuthentication should remain false") + } + + // MARK: - Cancel Flow: loginAsAdmin Clears on Cancel + + func testGivenLoginAsAdmin_whenCancelled_thenLoginAsAdminCleared() { + let request = makeAuthRequest() + request.loginAsAdmin = true + + XCTAssertTrue(request.loginAsAdmin, "loginAsAdmin should be true before cancel") + + // Simulate what the cancel handler does + request.loginAsAdmin = false + + XCTAssertFalse(request.loginAsAdmin, "loginAsAdmin should be false after cancel") + + // Creating a new session from the cleared request should not use browser auth + let session = SFSDKAuthSession(request, credentials: nil) + XCTAssertFalse(session.oauthCoordinator.useBrowserAuth, + "Coordinator should not use browser auth after loginAsAdmin is cleared") + } + + func testGivenLoginAsAdminCancelled_whenNewSession_thenAuthInfoMatchesGlobalSetting() { + createTestAppIdentity() + SalesforceManager.shared.useWebServerAuthentication = true + + let request = makeAuthRequest() + request.loginAsAdmin = true + + // Admin session uses advanced browser + let adminSession = SFSDKAuthSession(request, credentials: nil) + adminSession.oauthCoordinator.delegate = self + adminSession.oauthCoordinator.authenticate() + XCTAssertEqual(adminSession.oauthCoordinator.authInfo.authType, AuthInfo.AuthType.advancedBrowser) + adminSession.oauthCoordinator.stopAuthentication() + + // Simulate cancel + request.loginAsAdmin = false + + // New session from same request uses global setting + let normalSession = SFSDKAuthSession(request, credentials: nil) + normalSession.oauthCoordinator.delegate = self + normalSession.oauthCoordinator.authenticate() + XCTAssertEqual(normalSession.oauthCoordinator.authInfo.authType, AuthInfo.AuthType.webServer, + "After cancel, auth type should match global setting (webServer)") + normalSession.oauthCoordinator.stopAuthentication() + } + + // MARK: - Cancel Flow: Org-Initiated Browser Auth Unchanged + + func testGivenOrgInitiatedBrowserAuth_whenCancelled_thenUseBrowserAuthPreserved() { + let request = makeAuthRequest() + request.useBrowserAuth = true + request.loginAsAdmin = false + + XCTAssertFalse(request.loginAsAdmin, "loginAsAdmin should be false for org-initiated browser auth") + XCTAssertTrue(request.useBrowserAuth, "useBrowserAuth should be true for org-initiated browser auth") + + // After cancel of org-initiated auth, useBrowserAuth should remain true + let session = SFSDKAuthSession(request, credentials: nil) + XCTAssertTrue(session.oauthCoordinator.useBrowserAuth, + "Org-initiated browser auth should keep useBrowserAuth after cancel") + } + + // MARK: - useBrowserAuth Not Modified + + func testGivenLoginAsAdmin_whenFullLifecycle_thenUseBrowserAuthNeverMutated() { + let request = makeAuthRequest() + request.useBrowserAuth = false + + // Set loginAsAdmin + request.loginAsAdmin = true + XCTAssertFalse(request.useBrowserAuth, "useBrowserAuth should remain false after setting loginAsAdmin") + + // Create session - coordinator gets useBrowserAuth from the OR of both flags + let session = SFSDKAuthSession(request, credentials: nil) + XCTAssertTrue(session.oauthCoordinator.useBrowserAuth, "Coordinator should use browser auth") + XCTAssertFalse(request.useBrowserAuth, "Request useBrowserAuth should still be false") + + // Clear loginAsAdmin (cancel) + request.loginAsAdmin = false + XCTAssertFalse(request.useBrowserAuth, "useBrowserAuth should still be false after clearing loginAsAdmin") + + // New session should not use browser auth + let newSession = SFSDKAuthSession(request, credentials: nil) + XCTAssertFalse(newSession.oauthCoordinator.useBrowserAuth, "New coordinator should not use browser auth") + } + + // MARK: - SFLoginViewControllerDelegate Declaration + + func testGivenSFLoginViewControllerDelegate_thenLoginForAdminMethodExists() { + let manager = UserAccountManager.shared + XCTAssertTrue(manager.responds(to: NSSelectorFromString("loginViewControllerDidSelectLoginForAdmin:")), + "SFUserAccountManager should respond to loginViewControllerDidSelectLoginForAdmin:") + } + + // MARK: - SFUserAccountManager Cancel Browser Auth (loginAsAdmin path) + + func testGivenLoginAsAdmin_whenBrowserAuthCancelled_thenLoginAsAdminCleared() { + let request = makeAuthRequest() + request.loginAsAdmin = true + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = UserAccountManager.shared + + XCTAssertTrue(session.oauthRequest.loginAsAdmin, "loginAsAdmin should be true before cancel") + + // Call the cancel handler on the main thread (it dispatches to main if not already there) + UserAccountManager.shared.oauthCoordinatorDidCancelBrowserAuthentication(session.oauthCoordinator) + + XCTAssertFalse(session.oauthRequest.loginAsAdmin, "loginAsAdmin should be cleared after cancel") + } + + func testGivenLoginAsAdmin_whenBrowserAuthCancelled_thenUserCancelledNotificationNotPosted() { + let request = makeAuthRequest() + request.loginAsAdmin = true + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = UserAccountManager.shared + + var notificationPosted = false + let observer = NotificationCenter.default.addObserver( + forName: UserAccountManager.userCancelledAuthentication, + object: nil, queue: nil + ) { _ in + notificationPosted = true + } + + UserAccountManager.shared.oauthCoordinatorDidCancelBrowserAuthentication(session.oauthCoordinator) + + XCTAssertFalse(notificationPosted, + "kSFNotificationUserCancelledAuth should NOT be posted when loginAsAdmin cancel restarts auth") + + NotificationCenter.default.removeObserver(observer) + } + + func testGivenNoLoginAsAdmin_whenBrowserAuthCancelled_thenUserCancelledNotificationPosted() { + let request = makeAuthRequest() + request.loginAsAdmin = false + request.useBrowserAuth = false + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = UserAccountManager.shared + + // Set the handler block to avoid the server picker UI code path + var handlerCalled = false + UserAccountManager.shared.authCancelledByUserHandlerBlock = { + handlerCalled = true + } + + var notificationPosted = false + let observer = NotificationCenter.default.addObserver( + forName: UserAccountManager.userCancelledAuthentication, + object: nil, queue: nil + ) { _ in + notificationPosted = true + } + + UserAccountManager.shared.oauthCoordinatorDidCancelBrowserAuthentication(session.oauthCoordinator) + + XCTAssertTrue(notificationPosted, + "kSFNotificationUserCancelledAuth should be posted when loginAsAdmin is false") + XCTAssertTrue(handlerCalled, + "authCancelledByUserHandlerBlock should be called when loginAsAdmin is false") + + NotificationCenter.default.removeObserver(observer) + UserAccountManager.shared.authCancelledByUserHandlerBlock = nil + } + + func testGivenLoginAsAdmin_whenBrowserAuthCancelled_thenHandlerBlockNotCalled() { + let request = makeAuthRequest() + request.loginAsAdmin = true + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = UserAccountManager.shared + + var handlerCalled = false + UserAccountManager.shared.authCancelledByUserHandlerBlock = { + handlerCalled = true + } + + UserAccountManager.shared.oauthCoordinatorDidCancelBrowserAuthentication(session.oauthCoordinator) + + XCTAssertFalse(handlerCalled, + "authCancelledByUserHandlerBlock should NOT be called when loginAsAdmin cancel restarts auth") + + UserAccountManager.shared.authCancelledByUserHandlerBlock = nil + } + + // MARK: - SFUserAccountManager Cancel Browser Auth (nativeLogin fallback path) + + func testGivenNativeLoginFallback_whenBrowserAuthCancelled_thenFallbackConsumedAndRestartsNativeLogin() { + let request = makeAuthRequest() + request.loginAsAdmin = false + + let session = SFSDKAuthSession(request, credentials: nil) + session.oauthCoordinator.delegate = UserAccountManager.shared + + let uam = UserAccountManager.shared + let originalNativeLoginEnabled = uam.nativeLoginEnabled + let originalShouldFallback = uam.shouldFallbackToWebAuthentication + + // Simulate: native login set shouldFallbackToWebAuthentication = YES, + // which caused browser auth. The user is now cancelling that browser session. + uam.nativeLoginEnabled = true + uam.shouldFallbackToWebAuthentication = true + + var notificationPosted = false + let observer = NotificationCenter.default.addObserver( + forName: UserAccountManager.userCancelledAuthentication, + object: nil, queue: nil + ) { _ in + notificationPosted = true + } + + var handlerCalled = false + uam.authCancelledByUserHandlerBlock = { + handlerCalled = true + } + + uam.oauthCoordinatorDidCancelBrowserAuthentication(session.oauthCoordinator) + + // The fallback flag is consumed (set to NO) so the next loginWithCompletion: + // call returns to native login instead of launching another browser session. + XCTAssertFalse(uam.shouldFallbackToWebAuthentication, + "shouldFallbackToWebAuthentication should be consumed so next login attempt uses native login") + // This path returns early — no cancelled notification and no handler block call. + XCTAssertFalse(notificationPosted, + "kSFNotificationUserCancelledAuth should NOT be posted for native login fallback path") + XCTAssertFalse(handlerCalled, + "authCancelledByUserHandlerBlock should NOT be called for native login fallback path") + + NotificationCenter.default.removeObserver(observer) + uam.authCancelledByUserHandlerBlock = nil + uam.nativeLoginEnabled = originalNativeLoginEnabled + uam.shouldFallbackToWebAuthentication = originalShouldFallback + } + + // MARK: - SFUserAccountManager loginViewControllerDidSelectLoginForAdmin + + func testGivenAuthSession_whenLoginForAdminSelected_thenLoginAsAdminSetAndAuthRestarted() { + let uam = UserAccountManager.shared + + // Get the test app's active window scene to obtain a real sceneId + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { + XCTFail("Test requires a UIWindowScene from the running test app") + return + } + let sceneId = windowScene.session.persistentIdentifier + + // Create an auth session and seed it into authSessions with the real sceneId + let request = makeAuthRequest() + request.loginAsAdmin = false + let session = SFSDKAuthSession(request, credentials: nil) + uam.authSessions[sceneId as NSString] = session + + XCTAssertFalse(session.oauthRequest.loginAsAdmin, "loginAsAdmin should be false before selecting Login for Admin") + + // Create a SalesforceLoginViewController and place it in the window so its + // view.window.windowScene resolves to the same scene + let loginVC = SalesforceLoginViewController() + let window = windowScene.windows.first ?? UIWindow(windowScene: windowScene) + window.rootViewController = loginVC + window.makeKeyAndVisible() + loginVC.loadViewIfNeeded() + + // Call the delegate method via performSelector since the protocol conformance is internal + let selector = NSSelectorFromString("loginViewControllerDidSelectLoginForAdmin:") + uam.perform(selector, with: loginVC) + + XCTAssertTrue(session.oauthRequest.loginAsAdmin, + "loginAsAdmin should be true after loginViewControllerDidSelectLoginForAdmin:") + + // Clean up + uam.authSessions.removeObject(sceneId as NSString) + window.rootViewController = nil + } + + @available(*, deprecated, message: "Exercises deprecated public API") + func testGivenAuthSession_whenPublicLoginForAdminCalled_thenLoginAsAdminSet() { + let uam = UserAccountManager.shared + + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { + XCTFail("Test requires a UIWindowScene from the running test app") + return + } + let sceneId = windowScene.session.persistentIdentifier + + let request = makeAuthRequest() + request.loginAsAdmin = false + let session = SFSDKAuthSession(request, credentials: nil) + uam.authSessions[sceneId as NSString] = session + + XCTAssertFalse(session.oauthRequest.loginAsAdmin, "loginAsAdmin should be false before invoking public API") + + let loginVC = SalesforceLoginViewController() + let window = windowScene.windows.first ?? UIWindow(windowScene: windowScene) + window.rootViewController = loginVC + window.makeKeyAndVisible() + loginVC.loadViewIfNeeded() + + // Invoke directly via the public Swift binding (not performSelector) to confirm the + // method is exposed on UserAccountManager for SDK consumers. + uam.loginViewControllerDidSelectLoginForAdmin(loginVC) + + XCTAssertTrue(session.oauthRequest.loginAsAdmin, + "loginAsAdmin should be true after calling the public loginViewControllerDidSelectLoginForAdmin") + + uam.authSessions.removeObject(sceneId as NSString) + window.rootViewController = nil + } + + // MARK: - Private Helpers + + private func makeAuthRequest() -> SFSDKAuthRequest { + let request = SFSDKAuthRequest() + request.oauthClientId = "testClientId" + request.oauthCompletionUrl = "test://callback" + request.loginHost = "test.salesforce.com" + return request + } + + private func createTestAppIdentity() { + SalesforceManager.shared.bootConfig?.remoteAccessConsumerKey = "test_connected_app_id" + SalesforceManager.shared.bootConfig?.oauthRedirectURI = "test://callback" + SalesforceManager.shared.bootConfig?.oauthScopes = Set(["web", "api"]) + UserAccountManager.shared.oauthClientID = "test_connected_app_id" + } +} + +// MARK: - SFOAuthCoordinatorDelegate conformance for tests + +extension LoginForAdminTests: SFOAuthCoordinatorDelegate { + func oauthCoordinator(_ coordinator: SFOAuthCoordinator, didBeginAuthenticationWith view: WKWebView) {} + func oauthCoordinator(_ coordinator: SFOAuthCoordinator, didBeginAuthenticationWith session: ASWebAuthenticationSession) {} + func oauthCoordinatorDidBeginNativeAuthentication(_ coordinator: SFOAuthCoordinator) {} + func oauthCoordinatorDidCancelBrowserAuthentication(_ coordinator: SFOAuthCoordinator) {} +} diff --git a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLoginHostTests.m b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLoginHostTests.m index b151d17d68..42e5f4f825 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLoginHostTests.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLoginHostTests.m @@ -178,9 +178,9 @@ - (void) testLoginHostListViewControllerCreatesUniqueInstances { XCTAssertNotNil(instance2.config, "Second instance should have config"); XCTAssertNotNil(instance3.config, "Third instance should have config"); - XCTAssertEqual(instance1.delegate, loginViewController, "First instance delegate should be set to loginViewController"); - XCTAssertEqual(instance2.delegate, loginViewController, "Second instance delegate should be set to loginViewController"); - XCTAssertEqual(instance3.delegate, loginViewController, "Third instance delegate should be set to loginViewController"); + XCTAssertEqual((SFLoginViewController *)instance1.delegate, loginViewController, "First instance delegate should be set to loginViewController"); + XCTAssertEqual((SFLoginViewController *)instance2.delegate, loginViewController, "Second instance delegate should be set to loginViewController"); + XCTAssertEqual((SFLoginViewController *)instance3.delegate, loginViewController, "Third instance delegate should be set to loginViewController"); } @end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLogoutBlocker.m b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLogoutBlocker.m index bedb2f9f6e..819af8fcf8 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLogoutBlocker.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SFSDKLogoutBlocker.m @@ -25,7 +25,7 @@ #import "SFSDKLogoutBlocker.h" #import #import "SFSDKCoreLogger.h" -#import "SFUserAccountManager+Instrumentation.h" +#import "SFUserAccountManager.h" #import "SFOAuthCredentials.h" @interface SFSDKLogoutBlocker() diff --git a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKCoreTests-Bridging-Header.h b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKCoreTests-Bridging-Header.h index 4ec23d184d..5ec8f70c25 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKCoreTests-Bridging-Header.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKCoreTests-Bridging-Header.h @@ -2,4 +2,10 @@ // Use this file to import your target's public headers that you would like to expose to Swift. // #import +#import #import "SFSDKLogoutBlocker.h" +#import "SFSDKAuthRequest.h" +#import "SFSDKAuthSession.h" +#import "SFOAuthCoordinator+Internal.h" +#import "SFUserAccountManager+Internal.h" +#import "SFOAuthCredentials+Internal.h" diff --git a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKManagerTests.m b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKManagerTests.m index 1ef00bb709..920d8128cf 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKManagerTests.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceSDKManagerTests.m @@ -316,12 +316,6 @@ - (void)testNativeLoginManager #pragma mark - Process Pool Tests -- (void)testProcessPoolIsNil -{ - // TODO remove this test in 14.0 when we remove sharedProcessPool from SFSDKWebViewStateManager - XCTAssertNil(SFSDKWebViewStateManager.sharedProcessPool); -} - - (void)testBrandedLoginPath { NSString *brandPath = @"/BRAND/"; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/WebViewStateManagerTests.swift b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/WebViewStateManagerTests.swift index cfbf1d9a24..d6ee560e83 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/WebViewStateManagerTests.swift +++ b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/WebViewStateManagerTests.swift @@ -13,12 +13,6 @@ final class WebViewStateManagerTests: XCTestCase { try await super.tearDown() } - @MainActor - func testProcessPoolIsNil() { - // TODO remove this test in 14.0 when we remove sharedProcessPool from SFSDKWebViewStateManager - XCTAssertNil(SFSDKWebViewStateManager.sharedProcessPool) - } - @MainActor func testRemoveSessionForcefullyCallsCompletion() async { await SFSDKWebViewStateManager.removeSessionForcefully() diff --git a/libs/SmartStore/SmartStore.xcodeproj/project.pbxproj b/libs/SmartStore/SmartStore.xcodeproj/project.pbxproj index 877815a04d..d4164ebb95 100644 --- a/libs/SmartStore/SmartStore.xcodeproj/project.pbxproj +++ b/libs/SmartStore/SmartStore.xcodeproj/project.pbxproj @@ -56,8 +56,6 @@ B716A3D7218F6AD6009D407F /* SalesforceAnalytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B716A3B2218F6AAC009D407F /* SalesforceAnalytics.framework */; }; B716A3D8218F6AD6009D407F /* SalesforceSDKCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B716A3C0218F6AB3009D407F /* SalesforceSDKCommon.framework */; }; B716A3D9218F6AD6009D407F /* SalesforceSDKCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B716A3CE218F6ABA009D407F /* SalesforceSDKCore.framework */; }; - B78928412243DE5700BEDED4 /* SFSmartStore+Instrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = B789283F2243DE5700BEDED4 /* SFSmartStore+Instrumentation.h */; }; - B78928432243DE5700BEDED4 /* SFSmartStore+Instrumentation.m in Sources */ = {isa = PBXBuildFile; fileRef = B78928402243DE5700BEDED4 /* SFSmartStore+Instrumentation.m */; }; B7DD6CE61DC178D0004C04F4 /* SFMultipleSmartStoresTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B7DD6CE51DC178D0004C04F4 /* SFMultipleSmartStoresTests.m */; }; C03DE7E11D1B6B8E00BFA6BD /* SFSmartSqlTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C03DE7E01D1B6B8E00BFA6BD /* SFSmartSqlTests.m */; }; CE0AB0761C10D3AF00BFAEED /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CE4CE5841C0FB648009F6029 /* libz.tbd */; }; @@ -281,8 +279,6 @@ B716A3B9218F6AB3009D407F /* SalesforceSDKCommon.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SalesforceSDKCommon.xcodeproj; path = ../SalesforceSDKCommon/SalesforceSDKCommon.xcodeproj; sourceTree = ""; }; B716A3C5218F6ABA009D407F /* SalesforceSDKCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SalesforceSDKCore.xcodeproj; path = ../SalesforceSDKCore/SalesforceSDKCore.xcodeproj; sourceTree = ""; }; B7282F441D8C713C00475F79 /* SmartStoreTestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SmartStoreTestApp.entitlements; sourceTree = ""; }; - B789283F2243DE5700BEDED4 /* SFSmartStore+Instrumentation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFSmartStore+Instrumentation.h"; sourceTree = ""; }; - B78928402243DE5700BEDED4 /* SFSmartStore+Instrumentation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SFSmartStore+Instrumentation.m"; sourceTree = ""; }; B7DD6CE51DC178D0004C04F4 /* SFMultipleSmartStoresTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFMultipleSmartStoresTests.m; sourceTree = ""; }; C03DE7DF1D1B6B8E00BFA6BD /* SFSmartSqlTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFSmartSqlTests.h; sourceTree = ""; }; C03DE7E01D1B6B8E00BFA6BD /* SFSmartSqlTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFSmartSqlTests.m; sourceTree = ""; }; @@ -426,8 +422,6 @@ B789278D2242B2AD00BEDED4 /* Instrumentation */ = { isa = PBXGroup; children = ( - B789283F2243DE5700BEDED4 /* SFSmartStore+Instrumentation.h */, - B78928402243DE5700BEDED4 /* SFSmartStore+Instrumentation.m */, ); path = Instrumentation; sourceTree = ""; @@ -593,7 +587,6 @@ CE4CE41E1C0E59DA009F6029 /* SFSoupIndex.h in Headers */, CE4CE4161C0E59DA009F6029 /* SFSmartStoreDatabaseManager+Internal.h in Headers */, 4F75745222B9A96900528BE2 /* SFSmartSqlCache.h in Headers */, - B78928412243DE5700BEDED4 /* SFSmartStore+Instrumentation.h in Headers */, CE4CE40F1C0E59DA009F6029 /* SFSmartSqlHelper.h in Headers */, 829DA2AA1C1266F70040F5F1 /* SmartStore.h in Headers */, CE4CE4111C0E59DA009F6029 /* SFSmartStore.h in Headers */, @@ -899,7 +892,6 @@ CE4CE4211C0E59DA009F6029 /* SFStoreCursor.m in Sources */, CE4CE4181C0E59DA009F6029 /* SFSmartStoreInspectorViewController.m in Sources */, CE682C811F01B5E3003C43C0 /* SFSDKSmartStoreLogger.m in Sources */, - B78928432243DE5700BEDED4 /* SFSmartStore+Instrumentation.m in Sources */, CE4CE4121C0E59DA009F6029 /* SFSmartStore.m in Sources */, CE4CE4101C0E59DA009F6029 /* SFSmartSqlHelper.m in Sources */, CE4CE41F1C0E59DA009F6029 /* SFSoupIndex.m in Sources */, @@ -1176,7 +1168,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; XROS_DEPLOYMENT_TARGET = 2.0; @@ -1224,7 +1216,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; @@ -1372,7 +1364,7 @@ repositoryURL = "https://github.com/sqlcipher/SQLCipher.swift"; requirement = { kind = exactVersion; - version = 4.10.0; + version = 4.15.0; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/libs/SmartStore/SmartStore/Classes/Instrumentation/SFSmartStore+Instrumentation.h b/libs/SmartStore/SmartStore/Classes/Instrumentation/SFSmartStore+Instrumentation.h deleted file mode 100644 index 2b9ba5a755..0000000000 --- a/libs/SmartStore/SmartStore/Classes/Instrumentation/SFSmartStore+Instrumentation.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - SFRestAPI+Instrumentation.h - SalesforceSDKCore - Created by Raj Rao on 3/21/19. - - Copyright (c) 2019-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 - -NS_ASSUME_NONNULL_BEGIN - -@interface SFSmartStore (Instrumentation) - -@end - -NS_ASSUME_NONNULL_END diff --git a/libs/SmartStore/SmartStore/Classes/Instrumentation/SFSmartStore+Instrumentation.m b/libs/SmartStore/SmartStore/Classes/Instrumentation/SFSmartStore+Instrumentation.m deleted file mode 100644 index ac71914719..0000000000 --- a/libs/SmartStore/SmartStore/Classes/Instrumentation/SFSmartStore+Instrumentation.m +++ /dev/null @@ -1,311 +0,0 @@ -/* - SFRestAPI+Instrumentation.m - SalesforceSDKCore - Created by Raj Rao on 3/21/19. - - Copyright (c) 2019-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 "SFSmartStore+Instrumentation.h" -#import -#import -#import -#import -@interface SFSmartStore() -- (BOOL)firstTimeStoreDatabaseSetup; -- (BOOL)subsequentTimesStoreDatabaseSetup; -@end - -@implementation SFSmartStore (Instrumentation) - -+ (os_log_t)oslog { - static os_log_t _logger; - static dispatch_once_t pred; - dispatch_once(&pred, ^{ - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - _logger = os_log_create([appName cStringUsingEncoding:NSUTF8StringEncoding], [@"SFSmartStore" cStringUsingEncoding:NSUTF8StringEncoding]); - }); - return _logger; -} - - -+ (void)load{ - if ([SFSDKInstrumentationHelper isEnabled] && (self == SFSmartStore.self)) { - [self enableInstrumentation]; - } -} - -+ (void)enableInstrumentation { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - Class class = [self class]; - - SEL originalSelector = @selector(indicesForSoup:); - SEL swizzledSelector = @selector(instr_indicesForSoup:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(soupExists:); - swizzledSelector = @selector(instr_soupExists:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(registerSoup:withIndexSpecs:error:); - swizzledSelector = @selector(instr_registerSoup:withIndexSpecs:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(queryWithQuerySpec:pageIndex:error:); - swizzledSelector = @selector(instr_queryWithQuerySpec:pageIndex:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(queryAsString:querySpec:pageIndex:error:); - swizzledSelector = @selector(instr_queryAsString:querySpec:pageIndex:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(retrieveEntries:fromSoup:); - swizzledSelector = @selector(instr_retrieveEntries:fromSoup:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(upsertEntries:toSoup:); - swizzledSelector = @selector(instr_upsertEntries:toSoup:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(lookupSoupEntryIdForSoupName:forFieldPath:fieldValue:error:); - swizzledSelector = @selector(instr_lookupSoupEntryIdForSoupName:forFieldPath:fieldValue:error:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(removeEntries:fromSoup:); - swizzledSelector = @selector(instr_removeEntries:fromSoup:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(removeEntriesByQuery:fromSoup:); - swizzledSelector = @selector(instr_removeEntriesByQuery:fromSoup:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(clearSoup:); - swizzledSelector = @selector(instr_clearSoup:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(removeSoup:); - swizzledSelector = @selector(instr_removeSoup:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(removeAllSoups); - swizzledSelector = @selector(instr_removeAllSoups); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(alterSoup:withIndexSpecs:reIndexData:); - swizzledSelector = @selector(instr_alterSoup:withIndexSpecs:reIndexData:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(reIndexSoup:withIndexPaths:); - swizzledSelector = @selector(instr_reIndexSoup:withIndexPaths:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(reIndexSoup:withIndexPaths:); - swizzledSelector = @selector(instr_reIndexSoup:withIndexPaths:); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(firstTimeStoreDatabaseSetup); - swizzledSelector = @selector(instr_firstTimeStoreDatabaseSetup); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - originalSelector = @selector(subsequentTimesStoreDatabaseSetup); - swizzledSelector = @selector(instr_subsequentTimesStoreDatabaseSetup); - [SFSDKInstrumentationHelper swizzleMethod:originalSelector with:swizzledSelector forClass:class isInstanceMethod:YES]; - - - }); -} - -- (NSArray*)instr_indicesForSoup:(NSString*)soupName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "indicesForSoup", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - NSArray* indices = [self instr_indicesForSoup:soupName]; - sf_os_signpost_interval_end(logger, sid, "indicesForSoup", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return indices; -} - -- (BOOL)instr_soupExists:(NSString*)soupName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "soupExists", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - BOOL soupExists = [self instr_soupExists:soupName]; - sf_os_signpost_interval_end(logger, sid, "soupExists", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return soupExists; -} - -- (BOOL)instr_registerSoup:(NSString*)soupName withIndexSpecs:(NSArray*)indexSpecs error:(NSError**)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "registerSoup:withIndexSpecs:error", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - BOOL result = [self instr_registerSoup:soupName withIndexSpecs:indexSpecs error:error]; - sf_os_signpost_interval_end(logger, sid, "registerSoup:withIndexSpecs:error", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return result; -} - -- (NSArray *)instr_queryWithQuerySpec:(SFQuerySpec *)querySpec pageIndex:(NSUInteger)pageIndex error:(NSError **)error{ - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "queryWithQuerySpec:pageIndex:error:", "storeName:%{public}@ soupName:%{public}@", self.storeName, querySpec.soupName); - NSArray *result = [self instr_queryWithQuerySpec:querySpec pageIndex:pageIndex error:error]; - sf_os_signpost_interval_end(logger, sid, "queryWithQuerySpec:pageIndex:error:", "storeName:%{public}@ soupName:%{public}@", self.storeName, querySpec.soupName); - return result; -} - -- (BOOL)instr_queryAsString:(NSMutableString*)resultString querySpec:(SFQuerySpec *)querySpec pageIndex:(NSUInteger)pageIndex error:(NSError **)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "queryAsString:querySpec:pageIndex:error:", "storeName:%{public}@ soupName:%{public}@ query:%{public}@", self.storeName, querySpec.soupName,resultString); - BOOL result = [self instr_queryAsString:resultString querySpec:querySpec pageIndex:pageIndex error:error]; - sf_os_signpost_interval_end(logger, sid, "queryAsString:querySpec:pageIndex:error:", "storeName:%{public}@ soupName:%{public}@ query:%{public}@", self.storeName, querySpec.soupName,resultString); - return result; - -} - -- (NSArray*)instr_retrieveEntries:(NSArray*)soupEntryIds fromSoup:(NSString*)soupName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "retrieveEntries:fromSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - NSArray *result = [self instr_retrieveEntries:soupEntryIds fromSoup:soupName]; - sf_os_signpost_interval_end(logger, sid, "retrieveEntries:fromSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return result; -} - -- (NSArray*)instr_upsertEntries:(NSArray*)entries toSoup:(NSString*)soupName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "upsertEntries", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - NSArray *result = [self instr_upsertEntries:entries toSoup:soupName]; - sf_os_signpost_interval_end(logger, sid, "upsertEntries", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return result; -} - -- (NSArray *)instr_upsertEntries:(NSArray *)entries toSoup:(NSString *)soupName withExternalIdPath:(NSString *)externalIdPath error:(NSError **)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "upsertEntries:toSoup:withExternalIdPath:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - NSArray *result = [self instr_upsertEntries:entries toSoup:soupName withExternalIdPath:externalIdPath error:error]; - sf_os_signpost_interval_end(logger, sid, "upsertEntries:toSoup:withExternalIdPath:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return result; -} - -- (NSNumber *)instr_lookupSoupEntryIdForSoupName:(NSString *)soupName - forFieldPath:(NSString *)fieldPath - fieldValue:(NSString *)fieldValue - error:(NSError **)error{ - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "lookupSoupEntryIdForSoupName:forFieldPath:fieldValue:error:", "storeName:%{public}@ soupName:%{public}@ fieldPath:%{public}@ fieldValue:%{public}@", self.storeName, soupName,fieldPath,fieldValue); - NSNumber *result = [self instr_lookupSoupEntryIdForSoupName:soupName forFieldPath:fieldPath fieldValue:fieldValue error:error]; - sf_os_signpost_interval_end(logger, sid, "lookupSoupEntryIdForSoupName:forFieldPath:fieldValue:error:", "storeName:%{public}@ soupName:%{public}@ fieldPath:%{public}@ fieldValue:%{public}@", self.storeName, soupName,fieldPath,fieldValue); - return result; -} - - -- (void)instr_removeEntries:(NSArray*)entryIds fromSoup:(NSString*)soupName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "removeEntries:fromSoup:", "storeName:%{public}@ soupName:%{public}@ ", self.storeName, soupName); - [self instr_removeEntries:entryIds fromSoup:soupName]; - sf_os_signpost_interval_end(logger, sid, "removeEntries:fromSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); -} - -- (BOOL)instr_removeEntriesByQuery:(SFQuerySpec*)querySpec fromSoup:(NSString*)soupName error:(NSError **)error { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "removeEntries:fromSoup:error:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - BOOL result = [self instr_removeEntriesByQuery:querySpec fromSoup:soupName error:error]; - sf_os_signpost_interval_end(logger, sid, "removeEntries:fromSoup::error:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return result; -} - -- (void)instr_removeEntriesByQuery:(SFQuerySpec*)querySpec fromSoup:(NSString*)soupName{ - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "removeEntriesByQuery:fromSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - [self instr_removeEntriesByQuery:querySpec fromSoup:soupName]; - sf_os_signpost_interval_end(logger, sid, "removeEntriesByQuery:fromSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); -} - -- (void)instr_clearSoup:(NSString*)soupName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "clearSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - [self instr_clearSoup:soupName]; - sf_os_signpost_interval_end(logger, sid, "clearSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); -} - -- (void)instr_removeSoup:(NSString*)soupName { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "removeSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - [self instr_removeSoup:soupName]; - sf_os_signpost_interval_end(logger, sid, "removeSoup:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - } - -- (void)instr_removeAllSoups { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "removeAllSoups:", "storeName:%{public}@",self.storeName); - [self instr_removeAllSoups]; - sf_os_signpost_interval_end(logger, sid, "removeAllSoups:", "storeName:%{public}@",self.storeName); -} - -- (BOOL)instr_alterSoup:(NSString*)soupName withIndexSpecs:(NSArray*)indexSpecs reIndexData:(BOOL)reIndexData { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "alterSoup:withIndexSpecs:reIndexData:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - BOOL result = [self instr_alterSoup:soupName withIndexSpecs:indexSpecs reIndexData:reIndexData]; - sf_os_signpost_interval_end(logger, sid, "alterSoup:withIndexSpecs:reIndexData:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return result; -} - -- (BOOL)instr_reIndexSoup:(NSString*)soupName withIndexPaths:(NSArray*)indexPaths { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "reIndexSoup:withIndexPaths:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - BOOL result = [self instr_reIndexSoup:soupName withIndexPaths:indexPaths]; - sf_os_signpost_interval_end(logger, sid, "reIndexSoup:withIndexPaths:", "storeName:%{public}@ soupName:%{public}@", self.storeName, soupName); - return result; -} - -- (BOOL)instr_firstTimeStoreDatabaseSetup { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "firstTimeStoreDatabaseSetup", "storeName:%{public}@",self.storeName); - BOOL result = [self instr_firstTimeStoreDatabaseSetup]; - sf_os_signpost_interval_end(logger, sid, "firstTimeStoreDatabaseSetup", "storeName:%{public}@",self.storeName); - return result; - -} - -- (BOOL)instr_subsequentTimesStoreDatabaseSetup { - os_log_t logger = self.class.oslog; - os_signpost_id_t sid = sf_os_signpost_id_generate(logger); - sf_os_signpost_interval_begin(logger, sid, "subsequentTimesStoreDatabaseSetup", "storeName:%{public}@",self.storeName); - BOOL result = [self instr_subsequentTimesStoreDatabaseSetup]; - sf_os_signpost_interval_end(logger, sid, "subsequentTimesStoreDatabaseSetup", "storeName:%{public}@",self.storeName); - return result; -} -@end diff --git a/libs/SmartStore/SmartStoreTests/SFSmartStoreTests.m b/libs/SmartStore/SmartStoreTests/SFSmartStoreTests.m index 064d4e2e51..d287fcd05c 100644 --- a/libs/SmartStore/SmartStoreTests/SFSmartStoreTests.m +++ b/libs/SmartStore/SmartStoreTests/SFSmartStoreTests.m @@ -104,13 +104,13 @@ - (void) testRuntimeSettings - (void) testSqliteVersion { NSString* version = [NSString stringWithUTF8String:sqlite3_libversion()]; - XCTAssertEqualObjects(version, @"3.50.4"); + XCTAssertEqualObjects(version, @"3.53.0"); } - (void) testSqlCipherVersion { NSString* version = [self.store getSQLCipherVersion]; - XCTAssertEqualObjects(version, @"4.10.0 community"); + XCTAssertEqualObjects(version, @"4.15.0 community"); } - (void) testCipherProviderVersion diff --git a/mobilesdk_pods.rb b/mobilesdk_pods.rb index 9cda35ab8c..05a670047a 100644 --- a/mobilesdk_pods.rb +++ b/mobilesdk_pods.rb @@ -23,6 +23,9 @@ def use_mobile_sdk!(options={}) path = options[:path] ||= "./mobile_sdk/SalesforceMobileSDK-iOS" + source 'https://www.github.com/forcedotcom/SalesforceMobileSDK-iOS-Specs' + + pod 'SQLCipher', '4.15.0' pod 'SalesforceSDKCommon', :path => path pod 'SalesforceAnalytics', :path => path pod 'SalesforceSDKCore', :path => path @@ -43,19 +46,6 @@ def pod.build_type end -# Post Install: Enable sign posts -def signposts_post_install(installer) - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - if config.name == 'Debug' - config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'DEBUG=1','SIGNPOST_ENABLED=1'] - config.build_settings['OTHER_SWIFT_FLAGS'] = ['$(inherited)', '-DDEBUG','-DSIGNPOST_ENABLED'] - end - end - end -end - - # Post Install: Enable visionOS support def vision_os_post_install(installer) installer.pods_project.targets.each do |target| @@ -79,7 +69,7 @@ def mobile_sdk_post_install(installer) # Mobile SDK targets is_mobile_sdk_target = ['SalesforceAnalytics', 'SalesforceSDKCommon', 'SalesforceSDKCore', 'SmartStore', 'MobileSync', 'SalesforceReact', 'FMDB'].include?(target.name) if is_mobile_sdk_target - change_deployment_target(target, '17.0') + change_deployment_target(target, '18.0') end end end diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTester.xcodeproj/project.pbxproj b/native/SampleApps/AuthFlowTester/AuthFlowTester.xcodeproj/project.pbxproj index 574793ea7b..7234bebea8 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTester.xcodeproj/project.pbxproj +++ b/native/SampleApps/AuthFlowTester/AuthFlowTester.xcodeproj/project.pbxproj @@ -359,7 +359,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.salesforce.mobilesdk.AuthFlowTesterUITests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -379,7 +379,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.salesforce.mobilesdk.AuthFlowTesterUITests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -530,7 +530,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -560,7 +560,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown"; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift index 6c768a0b03..c504bbb7f5 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/PageObjects/LoginPageObject.swift @@ -81,6 +81,7 @@ class LoginPageObject { func performLogin(username: String, password: String) { setTextField(usernameField(), value: username) dismissKeyboardAfterTyping() + tap(loginButton()) setTextField(passwordField(), value: password) dismissKeyboardAfterTyping() tap(loginButton()) @@ -88,20 +89,37 @@ class LoginPageObject { } func performAdvancedLogin(username: String, password: String) { - // Fill password first so username field remains visible above the keyboard - tap(passwordField()) + setTextField(usernameField(), value: username) + usernameField().typeText(XCUIKeyboardKey.return.rawValue) setTextField(passwordField(), value: password) - // Now tap username field (visible above keyboard) and fill it - tap(usernameField()) + passwordField().typeText(XCUIKeyboardKey.return.rawValue) + tapIfPresent(allowButton()) + } + + /// Performs login via the "Login for Admin" flow. + /// Taps Settings → "Login for Admin" which triggers ASWebAuthenticationSession (native browser), + /// then completes authentication in the browser. + func performLoginForAdmin(username: String, password: String) { + // Tap Settings gear icon → "Login for Admin" menu item + tap(settingsButton()) + tap(loginForAdminButton()) + + // Wait for ASWebAuthenticationSession browser to appear + let topBar = app.otherElements["TopBrowserBar"] + _ = topBar.waitForExistence(timeout: UITestTimeouts.long) + + // Complete login in the browser (same interaction as advanced auth) setTextField(usernameField(), value: username) - // Press Return to submit the form usernameField().typeText(XCUIKeyboardKey.return.rawValue) + setTextField(passwordField(), value: password) + passwordField().typeText(XCUIKeyboardKey.return.rawValue) tapIfPresent(allowButton()) } func performWelcomeLogin(password: String) { + tap(loginButton()) setTextField(passwordField(), value: password) - tap(usernameFieldLabel()) // click on label to hide keyboard + dismissKeyboardAfterTyping() tap(loginButton()) tapIfPresent(allowButton()) } @@ -148,6 +166,10 @@ class LoginPageObject { private func loginOptionsButton() -> XCUIElement { return app.buttons["Login Options"] } + + private func loginForAdminButton() -> XCUIElement { + return app.buttons["Login for Admin"] + } private func changeServerNavigationBar() -> XCUIElement { return app.navigationBars["Change Server"] @@ -175,10 +197,15 @@ class LoginPageObject { /// Dismisses the keyboard after typing in a field. Tries the toolbar "Done" button first; /// if not found (e.g. on some simulators it is exposed as a Key, not Button), taps the - /// password label to dismiss. + /// password label or username label to dismiss. private func dismissKeyboardAfterTyping() { if !tapIfPresent(toolbarDoneButton()) { - tap(passwordFieldLabel()) + let passwordLabel = passwordFieldLabel() + if passwordLabel.exists { + passwordLabel.tap() + } else { + tap(usernameFieldLabel()) + } } } diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Tests/LoginForAdminTests.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Tests/LoginForAdminTests.swift new file mode 100644 index 0000000000..fb513aa23a --- /dev/null +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Tests/LoginForAdminTests.swift @@ -0,0 +1,67 @@ +/* + LoginForAdminTests.swift + AuthFlowTesterUITests + + Copyright (c) 2026-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 XCTest + +/// Tests for the "Login for Admin" feature which forces browser-based (ASWebAuthenticationSession) +/// authentication to support phishing-resistant MFA for admin users. +/// +/// The "Login for Admin" menu item in the login screen's Settings gear icon forces the +/// web server OAuth flow via native browser, regardless of the app's configured auth flow. +/// +/// These tests verify Login for Admin works: +/// - With web server flow enabled (default) +/// - With web server flow disabled (user agent flow) - Login for Admin should still use web server flow +/// +/// NB: Tests use the first user from ui_test_config.json +/// +class LoginForAdminTests: BaseAuthFlowTester { + + // MARK: - Login for Admin with Web Server Flow Enabled + + /// Login for Admin with ECA opaque app, web server flow enabled (default). + /// Verifies the admin browser auth flow works when web server flow is already the default. + func testLoginForAdmin_WebServerFlowEnabled() throws { + launchLoginAndValidate( + staticAppConfigName: .ecaOpaque, + loginForAdmin: true + ) + } + + // MARK: - Login for Admin with Web Server Flow Disabled + + /// Login for Admin with ECA opaque app, web server flow disabled. + /// Verifies Login for Admin forces web server flow even when the app is configured + /// to use user agent flow. + func testLoginForAdmin_WebServerFlowDisabled() throws { + launchLoginAndValidate( + staticAppConfigName: .ecaOpaque, + useWebServerFlow: false, + loginForAdmin: true + ) + } +} diff --git a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/BaseAuthFlowTester.swift b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/BaseAuthFlowTester.swift index 49f3a34333..81d321f959 100644 --- a/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/BaseAuthFlowTester.swift +++ b/native/SampleApps/AuthFlowTester/AuthFlowTesterUITests/Util/BaseAuthFlowTester.swift @@ -93,6 +93,7 @@ class BaseAuthFlowTester: XCTestCase { /// - useWebServerFlow: Whether to use web server OAuth flow. Defaults to `true`. /// - useHybridFlow: Whether to use hybrid authentication flow. Defaults to `true`. /// - useWelcomeDiscovery: When true, configures simulated domain discovery. Defaults to `false`. + /// - loginForAdmin: When true, uses the "Login for Admin" flow (browser-based auth via Settings menu). Defaults to `false`. func login( loginHost: KnownLoginHostConfig, user: KnownUserConfig, @@ -103,6 +104,7 @@ class BaseAuthFlowTester: XCTestCase { useWebServerFlow: Bool = true, useHybridFlow: Bool = true, useWelcomeDiscovery: Bool = false, + loginForAdmin: Bool = false, ) { let userConfig = getUser(loginHost: loginHost, user: user) let hostConfig = getLoginHost(loginHost: loginHost) @@ -136,8 +138,12 @@ class BaseAuthFlowTester: XCTestCase { return } + // Login for Admin (browser-based auth via Settings menu) + if (loginForAdmin) { + loginPage.performLoginForAdmin(username: userConfig.username, password: userConfig.password) + } // Welcome login - if (useWelcomeDiscovery) { + else if (useWelcomeDiscovery) { XCTAssertTrue(loginPage.hasFilledUsernameField(username: userConfig.username), "Login page should have pre-filled username") loginPage.performWelcomeLogin(password: userConfig.password) } @@ -263,10 +269,11 @@ class BaseAuthFlowTester: XCTestCase { dynamicScopeSelection: ScopeSelection = .empty, useWebServerFlow: Bool = true, useHybridFlow: Bool = true, + loginForAdmin: Bool = false, ) { // Launch launch() - + // Login login( loginHost: loginHost, @@ -277,6 +284,7 @@ class BaseAuthFlowTester: XCTestCase { dynamicScopeSelection: dynamicScopeSelection, useWebServerFlow: useWebServerFlow, useHybridFlow: useHybridFlow, + loginForAdmin: loginForAdmin, ) } @@ -305,14 +313,15 @@ class BaseAuthFlowTester: XCTestCase { useWebServerFlow: Bool = true, useHybridFlow: Bool = true, useWelcomeDiscovery: Bool = false, + loginForAdmin: Bool = false, ) { let useStaticConfiguration = dynamicAppConfigName == nil let userAppConfigName = useStaticConfiguration ? staticAppConfigName : dynamicAppConfigName! let userScopeSelection = useStaticConfiguration ? staticScopeSelection : dynamicScopeSelection - + // Launch launch() - + // Login login( loginHost: loginHost, @@ -323,10 +332,13 @@ class BaseAuthFlowTester: XCTestCase { dynamicScopeSelection: dynamicScopeSelection, useWebServerFlow: useWebServerFlow, useHybridFlow: useHybridFlow, - useWelcomeDiscovery: useWelcomeDiscovery + useWelcomeDiscovery: useWelcomeDiscovery, + loginForAdmin: loginForAdmin ) - + // Validate + // Login for Admin always uses web server flow regardless of the useWebServerFlow setting + let effectiveUseWebServerFlow = loginForAdmin || useWebServerFlow validate( loginHost: loginHost, user: user, @@ -334,7 +346,7 @@ class BaseAuthFlowTester: XCTestCase { staticScopeSelection: staticScopeSelection, userAppConfigName: userAppConfigName, userScopeSelection: userScopeSelection, - useWebServerFlow: useWebServerFlow, + useWebServerFlow: effectiveUseWebServerFlow, useHybridFlow: useHybridFlow ) } diff --git a/native/SampleApps/MobileSyncExplorer/MobileSyncExplorer.xcodeproj/project.pbxproj b/native/SampleApps/MobileSyncExplorer/MobileSyncExplorer.xcodeproj/project.pbxproj index 93ecff0569..c54bc9fc95 100644 --- a/native/SampleApps/MobileSyncExplorer/MobileSyncExplorer.xcodeproj/project.pbxproj +++ b/native/SampleApps/MobileSyncExplorer/MobileSyncExplorer.xcodeproj/project.pbxproj @@ -953,7 +953,7 @@ "$(BUILT_PRODUCTS_DIR)/Headers", "$(OBJROOT)/UninstalledProducts/Headers", ); - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LIBRARY_SEARCH_PATHS = ""; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -1010,7 +1010,7 @@ "$(BUILT_PRODUCTS_DIR)/Headers", "$(OBJROOT)/UninstalledProducts/Headers", ); - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; LIBRARY_SEARCH_PATHS = ""; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; @@ -1178,7 +1178,7 @@ repositoryURL = "https://github.com/sqlcipher/SQLCipher.swift"; requirement = { kind = exactVersion; - version = 4.10.0; + version = 4.15.0; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/native/SampleApps/RestAPIExplorer/RestAPIExplorer.xcodeproj/project.pbxproj b/native/SampleApps/RestAPIExplorer/RestAPIExplorer.xcodeproj/project.pbxproj index 0db5d29bdd..aa31f1135a 100644 --- a/native/SampleApps/RestAPIExplorer/RestAPIExplorer.xcodeproj/project.pbxproj +++ b/native/SampleApps/RestAPIExplorer/RestAPIExplorer.xcodeproj/project.pbxproj @@ -660,7 +660,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -716,7 +716,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/readme.md b/readme.md index c40c3dbafc..cc1ef9bb6d 100644 --- a/readme.md +++ b/readme.md @@ -27,12 +27,12 @@ After cloning the repo: This script pulls the submodule dependencies from GitHub, to finalize setup of the workspace. You can then work with the Mobile SDK by opening `SalesforceMobileSDK.xcworkspace` from Xcode. -The Salesforce Mobile SDK for iOS requires iOS 17.0 or greater. The install.sh script checks for this, and aborts if the configured SDK version is incorrect. +The Salesforce Mobile SDK for iOS requires iOS 18.0 or greater. The install.sh script checks for this, and aborts if the configured SDK version is incorrect. Introduction == -### What's New in 13.2.0 +### What's New in 14.0.0 See [release notes](https://github.com/forcedotcom/SalesforceMobileSDK-iOS/releases). ### Native Applications diff --git a/shared/resources/SalesforceSDKResources.bundle/en.lproj/Localizable.strings b/shared/resources/SalesforceSDKResources.bundle/en.lproj/Localizable.strings index 2962ebb46d..0e29c6ccc1 100644 --- a/shared/resources/SalesforceSDKResources.bundle/en.lproj/Localizable.strings +++ b/shared/resources/SalesforceSDKResources.bundle/en.lproj/Localizable.strings @@ -68,6 +68,7 @@ "LOGIN_SETTINGS_BUTTON" = "Settings"; "LOGIN_OPTIONS" = "Login Options"; +"LOGIN_FOR_ADMIN" = "Login for Admin"; "LOGIN_CLEAR_COOKIES" = "Clear Cookies"; "LOGIN_CLEAR_CACHE" = "Clear Cache"; "LOGIN_RELOAD" = "Reload";