Skip to content

Commit

Permalink
[ABW-2735] AppsFlyer integration (#1073)
Browse files Browse the repository at this point in the history
Co-authored-by: Duje Begonja RDX <108268552+duje-begonja-rdx@users.noreply.github.com>
  • Loading branch information
matiasbzurovski and duje-begonja-rdx committed Apr 5, 2024
1 parent 9523d0e commit 6a66d1a
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 6 deletions.
1 change: 1 addition & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ jobs:
git config user.name $GIT_USER
git config user.email $GIT_USER
echo "${{ env.WALLET_FASTLANE_SECRETS_BASE64 }}" | base64 --decode > fastlane/.env.secret
echo "${{ env.WALLET_GENERAL_SECRETS_BASE64 }}" | base64 --decode > .env.secret
brew install xcbeautify
env:
GIT_USER: ${{ env.WALLET_RADIX_BOT_USERNAME }}
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ DerivedData/
.netrc
fastlane/report.xml
fastlane/test_output/
fastlane/.env.secret
.env.secret
.bundle
vendor
.design
.design
Aux/SensitiveInfo.plist
10 changes: 10 additions & 0 deletions Aux/SensitiveInfo-Sample.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>APPS_FLYER_APP_ID</key>
<string>placeholder</string>
<key>APPS_FLYER_DEV_KEY</key>
<string>placeholder</string>
</dict>
</plist>
76 changes: 76 additions & 0 deletions RadixWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,12 @@
48FFFB082ADC6FD300B2B213 /* SwiftUINavigationCore in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB072ADC6FD300B2B213 /* SwiftUINavigationCore */; };
48FFFB0A2ADC721800B2B213 /* Atomics in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB092ADC721800B2B213 /* Atomics */; };
48FFFB0D2ADC744700B2B213 /* TextBuilder in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB0C2ADC744700B2B213 /* TextBuilder */; };
5B1C4FD52BBB0B0C00B9436F /* AppsFlyerLib-Strict in Frameworks */ = {isa = PBXBuildFile; productRef = 5B1C4FD42BBB0B0C00B9436F /* AppsFlyerLib-Strict */; };
5B1C4FD82BBB0C1E00B9436F /* AppsFlyerClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B1C4FD72BBB0C1E00B9436F /* AppsFlyerClient+Interface.swift */; };
5B1C4FDA2BBB0DCF00B9436F /* AppsFlyerClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B1C4FD92BBB0DCF00B9436F /* AppsFlyerClient+Live.swift */; };
5B9846BD2BBD5C8800E814F3 /* SensitiveInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */; };
5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */; };
5B9846C22BBD5F7600E814F3 /* SensitiveInfoClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9846C12BBD5F7600E814F3 /* SensitiveInfoClient+Live.swift */; };
5BBC43A92BBAC6B0005747B1 /* AppTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BBC43A82BBAC6B0005747B1 /* AppTextEditor.swift */; };
830818482B9F1621002D8351 /* HTTPClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830818472B9F1621002D8351 /* HTTPClient+Live.swift */; };
8308184A2B9F162B002D8351 /* HTTPClient+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830818492B9F162B002D8351 /* HTTPClient+Mock.swift */; };
Expand Down Expand Up @@ -2382,6 +2388,11 @@
48F9CFE62B03A0A000657755 /* ProfileBuilderTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileBuilderTest.swift; sourceTree = "<group>"; };
48FF43142AE43C7C00C568B9 /* TimeLimit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeLimit.swift; sourceTree = "<group>"; };
48FFFAF12ADC23AC00B2B213 /* Exports.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exports.swift; sourceTree = "<group>"; };
5B1C4FD72BBB0C1E00B9436F /* AppsFlyerClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppsFlyerClient+Interface.swift"; sourceTree = "<group>"; };
5B1C4FD92BBB0DCF00B9436F /* AppsFlyerClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppsFlyerClient+Live.swift"; sourceTree = "<group>"; };
5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SensitiveInfo.plist; sourceTree = "<group>"; };
5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SensitiveInfoClient+Interface.swift"; sourceTree = "<group>"; };
5B9846C12BBD5F7600E814F3 /* SensitiveInfoClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SensitiveInfoClient+Live.swift"; sourceTree = "<group>"; };
5BBC43A82BBAC6B0005747B1 /* AppTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTextEditor.swift; sourceTree = "<group>"; };
830818472B9F1621002D8351 /* HTTPClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HTTPClient+Live.swift"; sourceTree = "<group>"; };
830818492B9F162B002D8351 /* HTTPClient+Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HTTPClient+Mock.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2649,6 +2660,7 @@
48FFFAFB2ADC241A00B2B213 /* HashTreeCollections in Frameworks */,
48FFFAC52ADC211700B2B213 /* JSONTesting in Frameworks */,
48FFFB062ADC6FD300B2B213 /* SwiftUINavigation in Frameworks */,
5B1C4FD52BBB0B0C00B9436F /* AppsFlyerLib-Strict in Frameworks */,
48FFFB032ADC6F8100B2B213 /* Builders in Frameworks */,
48FFFAB72ADC207B00B2B213 /* NavigationTransitions in Frameworks */,
48FFFA992ADC1EEC00B2B213 /* AsyncExtensions in Frameworks */,
Expand Down Expand Up @@ -5080,6 +5092,8 @@
48CFBF522ADC10D900E77A5C /* Clients */ = {
isa = PBXGroup;
children = (
5B9846BE2BBD5EF600E814F3 /* SensitiveInfoClient */,
5B1C4FD62BBB0C0100B9436F /* AppsFlyerClient */,
8370FC5A2B99C732007AD882 /* NPSSurveyClient */,
83823EA82B72362600827211 /* TokenPriceClient */,
83823EA52B722D9000827211 /* HTTPClient */,
Expand Down Expand Up @@ -6690,6 +6704,7 @@
48CFC6972ADC110800E77A5C /* InfoPlist.strings */,
48CFC6992ADC110800E77A5C /* Config */,
48CFC6AD2ADC110800E77A5C /* Radix-Wallet--iOS--Info.plist */,
5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */,
);
path = Aux;
sourceTree = "<group>";
Expand Down Expand Up @@ -6771,6 +6786,24 @@
path = KeychainClientTests;
sourceTree = "<group>";
};
5B1C4FD62BBB0C0100B9436F /* AppsFlyerClient */ = {
isa = PBXGroup;
children = (
5B1C4FD72BBB0C1E00B9436F /* AppsFlyerClient+Interface.swift */,
5B1C4FD92BBB0DCF00B9436F /* AppsFlyerClient+Live.swift */,
);
path = AppsFlyerClient;
sourceTree = "<group>";
};
5B9846BE2BBD5EF600E814F3 /* SensitiveInfoClient */ = {
isa = PBXGroup;
children = (
5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */,
5B9846C12BBD5F7600E814F3 /* SensitiveInfoClient+Live.swift */,
);
path = SensitiveInfoClient;
sourceTree = "<group>";
};
830EA9D42AE94014004C8051 /* AccountAndPersonaHidingFeature */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -7661,6 +7694,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 48CFBC5D2ADC106400E77A5C /* Build configuration list for PBXNativeTarget "RadixWallet" */;
buildPhases = (
5B9846C32BBD643700E814F3 /* Create SensitiveInfo Sample */,
48CFBC4B2ADC106300E77A5C /* Sources */,
48CFBC4C2ADC106300E77A5C /* Frameworks */,
48CFBC4D2ADC106300E77A5C /* Resources */,
Expand Down Expand Up @@ -7712,6 +7746,7 @@
E63D123C2ADD1FC00001CBB1 /* SwiftUIIntrospect */,
A47571FE2B29B0860059A95D /* IOSSecuritySuite */,
A415574F2B757C5E0040AD4E /* ComposableArchitecture */,
5B1C4FD42BBB0B0C00B9436F /* AppsFlyerLib-Strict */,
);
productName = RadixWallet;
productReference = 48CFBC4F2ADC106300E77A5C /* Radix Wallet Dev.app */;
Expand Down Expand Up @@ -7781,6 +7816,7 @@
48FFFB0B2ADC744700B2B213 /* XCRemoteSwiftPackageReference "TextBuilder" */,
A47571FD2B29B0860059A95D /* XCRemoteSwiftPackageReference "IOSSecuritySuite" */,
A415574E2B757C5E0040AD4E /* XCRemoteSwiftPackageReference "swift-composable-architecture" */,
5B1C4FD32BBB0B0C00B9436F /* XCRemoteSwiftPackageReference "AppsFlyerFramework-Strict" */,
);
productRefGroup = 48CFBC502ADC106300E77A5C /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -7833,6 +7869,7 @@
48CFC6B82ADC110800E77A5C /* Project-Debug-Opt.xcconfig in Resources */,
48CFC6BD2ADC110800E77A5C /* Project-Beta.xcconfig in Resources */,
48CFC6B02ADC110800E77A5C /* iOS-dev.xcconfig in Resources */,
5B9846BD2BBD5C8800E814F3 /* SensitiveInfo.plist in Resources */,
48CFC6AE2ADC110800E77A5C /* InfoPlist.strings in Resources */,
48CFC5F72ADC10DA00E77A5C /* IBMPlexSans-Medium.ttf in Resources */,
48CFC6B32ADC110800E77A5C /* iOS-shared.xcconfig in Resources */,
Expand All @@ -7853,6 +7890,28 @@
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
5B9846C32BBD643700E814F3 /* Create SensitiveInfo Sample */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Create SensitiveInfo Sample";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/SensitiveInfo.plist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# The SensitiveInfo.plist contains the secret tokens that we don't want publicly available.\n# As this file is ignored from SourceControl, this script will create a placeholder version\n# of it if it isn't already present.\nCONFIG_FILE_BASE_NAME=\"SensitiveInfo\"\n \nCONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}.plist\nSAMPLE_CONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}-Sample.plist\n \nCONFIG_FILE_PATH=$SRCROOT/Aux/$CONFIG_FILE_NAME\nSAMPLE_CONFIG_FILE_PATH=$SRCROOT/Aux/$SAMPLE_CONFIG_FILE_NAME\n \nif [ -f \"$CONFIG_FILE_PATH\" ]; then\n echo \"$CONFIG_FILE_PATH exists.\"\nelse\n echo \"$CONFIG_FILE_PATH does not exist, copying sample\"\n cp -v \"${SAMPLE_CONFIG_FILE_PATH}\" \"${CONFIG_FILE_PATH}\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
481B43AC2ADC7F1A007945C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
Expand Down Expand Up @@ -8400,9 +8459,11 @@
48CFC66D2ADC10DB00E77A5C /* SecurityQuestionsFactorSource.swift in Sources */,
48CFC6022ADC10DA00E77A5C /* P2P+LedgerHardwareWallet.swift in Sources */,
48CFC46A2ADC10DA00E77A5C /* ImportLegacyWalletClient+Live.swift in Sources */,
5B1C4FD82BBB0C1E00B9436F /* AppsFlyerClient+Interface.swift in Sources */,
830EA9D62AE94033004C8051 /* AccountAndPersonaHiding+Reducer.swift in Sources */,
48CFC5052ADC10DA00E77A5C /* TransactionPreviewResponseLogsInner.swift in Sources */,
48CFC2FF2ADC10D900E77A5C /* AccountSecurity+View.swift in Sources */,
5B1C4FDA2BBB0DCF00B9436F /* AppsFlyerClient+Live.swift in Sources */,
48CFC56B2ADC10DA00E77A5C /* MetadataU8ArrayValue.swift in Sources */,
A4CFB55F2BAA821E00778BDD /* HScrollBar.swift in Sources */,
48CFC2F92ADC10D900E77A5C /* InfoOfNewPersona+Reducer.swift in Sources */,
Expand Down Expand Up @@ -8760,6 +8821,7 @@
48CFC3EE2ADC10D900E77A5C /* DataChannelAssembledMessage.swift in Sources */,
48CFC2972ADC10D900E77A5C /* AdvancedFeesCustomization.swift in Sources */,
48CFC4CB2ADC10DA00E77A5C /* Extensions.swift in Sources */,
5B9846C22BBD5F7600E814F3 /* SensitiveInfoClient+Live.swift in Sources */,
48CFC4302ADC10DA00E77A5C /* Collection+Extra.swift in Sources */,
83EE47832AF0EE3C00155F03 /* ProgrammaticScryptoSborValuePreciseDecimal.swift in Sources */,
48CFC2D62ADC10D900E77A5C /* ChooseAccountsRow.swift in Sources */,
Expand Down Expand Up @@ -8910,6 +8972,7 @@
48CFC6332ADC10DB00E77A5C /* UnsecuredEntityControl.swift in Sources */,
48CFC4D32ADC10DA00E77A5C /* StreamTransactionsRequest.swift in Sources */,
48CFC64D2ADC10DB00E77A5C /* PersonaData+PostalAddress.swift in Sources */,
5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */,
48CFC5EE2ADC10DA00E77A5C /* SlideUpPanel+View.swift in Sources */,
48CFC3492ADC10D900E77A5C /* PersonaDataPermissionBox.swift in Sources */,
5BBC43A92BBAC6B0005747B1 /* AppTextEditor.swift in Sources */,
Expand Down Expand Up @@ -9802,6 +9865,14 @@
minimumVersion = 3.0.1;
};
};
5B1C4FD32BBB0B0C00B9436F /* XCRemoteSwiftPackageReference "AppsFlyerFramework-Strict" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/AppsFlyerSDK/AppsFlyerFramework-Strict";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 6.13.2;
};
};
A415574E2B757C5E0040AD4E /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture";
Expand Down Expand Up @@ -10011,6 +10082,11 @@
package = 48FFFB0B2ADC744700B2B213 /* XCRemoteSwiftPackageReference "TextBuilder" */;
productName = TextBuilder;
};
5B1C4FD42BBB0B0C00B9436F /* AppsFlyerLib-Strict */ = {
isa = XCSwiftPackageProductDependency;
package = 5B1C4FD32BBB0B0C00B9436F /* XCRemoteSwiftPackageReference "AppsFlyerFramework-Strict" */;
productName = "AppsFlyerLib-Strict";
};
A415574F2B757C5E0040AD4E /* ComposableArchitecture */ = {
isa = XCSwiftPackageProductDependency;
package = A415574E2B757C5E0040AD4E /* XCRemoteSwiftPackageReference "swift-composable-architecture" */;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"originHash" : "3313f884630244f405efa4cdbbcb2486d097b16289931114ea3c6826384f24b9",
"pins" : [
{
"identity" : "anycodable",
Expand All @@ -9,6 +10,15 @@
"version" : "0.6.7"
}
},
{
"identity" : "appsflyerframework-strict",
"kind" : "remoteSourceControl",
"location" : "https://github.com/AppsFlyerSDK/AppsFlyerFramework-Strict",
"state" : {
"revision" : "a22ea3af34d4631123bd54f55f95f7b7a9cd905f",
"version" : "6.13.2"
}
},
{
"identity" : "asyncextensions",
"kind" : "remoteSourceControl",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// MARK: - AppsFlyerClient
struct AppsFlyerClient: Sendable {
var start: Start
}

// MARK: AppsFlyerClient.Start
extension AppsFlyerClient {
typealias Start = @Sendable () -> Void
}

extension DependencyValues {
var appsFlyerClient: AppsFlyerClient {
get { self[AppsFlyerClient.self] }
set { self[AppsFlyerClient.self] = newValue }
}
}
26 changes: 26 additions & 0 deletions RadixWallet/Clients/AppsFlyerClient/AppsFlyerClient+Live.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import AppsFlyerLib

extension AppsFlyerClient: DependencyKey {
static var liveValue: AppsFlyerClient {
@Dependency(\.sensitiveInfoClient) var sensitiveInfoClient

return .init(
start: {
guard
let devKey = sensitiveInfoClient.read(.appsFlyerDevKey),
let appId = sensitiveInfoClient.read(.appsFlyerAppId)
else {
return
}
AppsFlyerLib.shared().appsFlyerDevKey = devKey
AppsFlyerLib.shared().appleAppID = appId

#if DEBUG
AppsFlyerLib.shared().isDebug = true
#endif

AppsFlyerLib.shared().start()
}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// MARK: - SensitiveInfoClient
struct SensitiveInfoClient: Sendable {
var read: Read
}

// MARK: SensitiveInfoClient.Read
extension SensitiveInfoClient {
typealias Read = @Sendable (_ key: Key) -> String?
}

extension DependencyValues {
var sensitiveInfoClient: SensitiveInfoClient {
get { self[SensitiveInfoClient.self] }
set { self[SensitiveInfoClient.self] = newValue }
}
}

// MARK: - SensitiveInfoClient.Key
extension SensitiveInfoClient {
enum Key: String {
case appsFlyerAppId = "APPS_FLYER_APP_ID"
case appsFlyerDevKey = "APPS_FLYER_DEV_KEY"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
extension SensitiveInfoClient: DependencyKey {
static var liveValue: SensitiveInfoClient {
.init(
read: { key in
guard let filePath = Bundle.main.path(forResource: "SensitiveInfo", ofType: "plist") else {
assertionFailure("Couldn't find file 'SensitiveInfo.plist'")
return nil
}
let plist = NSDictionary(contentsOfFile: filePath)
guard let value = plist?.object(forKey: key.rawValue) as? String else {
assertionFailure("Couldn't find value for key '\(key.rawValue)' in 'SensitiveInfo.plist'.")
return nil
}
if value.starts(with: "placeholder") {
loggerGlobal.warning("Please set up your sensitive info tokens in 'SensitiveInfo.plist'")
}
return value
}
)
}
}
7 changes: 7 additions & 0 deletions RadixWallet/Features/AppFeature/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,11 @@ public final class AppDelegate: NSObject, UIApplicationDelegate {
sceneConfig.delegateClass = SceneDelegate.self
return sceneConfig
}

public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
@Dependency(\.appsFlyerClient) var appsFlyerClient
appsFlyerClient.start()

return true
}
}
13 changes: 10 additions & 3 deletions SETUP_DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,16 @@ gem install bundler -v 2.3.25
bundle install
```

### Setup secrets

There are two types of secrets required by the project: `General` & `Fastlane`. In order to download them, you will need access to RDX Works 1Password team.
Once you have it, you will be to download each secrets file and place it in the folder detailed in the next steps. After downloading each file, be sure to remove the leading underscore from the file name.

- Download [general secrets][general_secrets] and put the downloaded file in root folder.
- Download [fastlane secrets][fastlane_secrets] and put the downloaded file in [fastlane](fastlane) folder.

### Setup `fastlane`

- Download [fastlane secrets][secret] (requires RDX Works 1Password access).
- Put the downloaded file in [fastlane](fastlane) folder. Be sure to remove the leading underscore from the file name.
- Run the below command to bring the necessary certificates for development:

```sh
Expand All @@ -58,4 +64,5 @@ After the above setup, you are good to go with building and running the app on i

[rbenv]: https://github.com/rbenv/rbenv
[bundler]: https://bundler.io
[secret]: https://start.1password.com/open/i?a=JWO4INKPOFHCDMZ2CYQMY4DRY4&v=srjnzoh2conosxfpkekxlakwzq&i=c75l3mugtfopfd5ebrcn22hssu&h=rdxworks.1password.com
[general_secrets]: https://start.1password.com/open/i?a=JWO4INKPOFHCDMZ2CYQMY4DRY4&v=btoakzspnaugf5miuybcfh5fey&i=hb34e2be37ep5cym3vo7fuvsu4&h=rdxworks.1password.com
[fastlane_secrets]: https://start.1password.com/open/i?a=JWO4INKPOFHCDMZ2CYQMY4DRY4&v=btoakzspnaugf5miuybcfh5fey&i=xpfwvtmc65hbja4xwujp2e6vfq&h=rdxworks.1password.com
Loading

0 comments on commit 6a66d1a

Please sign in to comment.