From 75f1d1ecc291ebb8e9fce18e3df498618b7ecbc8 Mon Sep 17 00:00:00 2001 From: Zdravko Iliev <zdravko.iliev@vereign.com> Date: Mon, 18 Mar 2024 10:32:05 +0000 Subject: [PATCH] feat: implement universal/app links --- android/app/src/main/AndroidManifest.xml | 21 +++++++++ .../project.pbxproj | 10 +++- ios/VereignCredentialManager/AppDelegate.mm | 8 ++++ .../VereignCredentialManager.entitlements | 12 +++++ src/navigators/RootStack.tsx | 47 ++++++++++++++----- 5 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 ios/VereignCredentialManager/VereignCredentialManager.entitlements diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8f90ab4..8e943fe 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -33,6 +33,27 @@ <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="com.vereign.vcm" /> </intent-filter> + <intent-filter android:autoVerify="true"> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="https" /> + <data android:host="holder-dev.vereign.com" /> + </intent-filter> + <intent-filter android:autoVerify="true"> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="https" /> + <data android:host="agent.hinpoc.ch" /> + </intent-filter> + <intent-filter android:autoVerify="true"> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="https" /> + <data android:host="issuer-dev.vereign.com" /> + </intent-filter> </activity> </application> <queries> diff --git a/ios/VereignCredentialManager.xcodeproj/project.pbxproj b/ios/VereignCredentialManager.xcodeproj/project.pbxproj index b31c5e3..ad056fd 100644 --- a/ios/VereignCredentialManager.xcodeproj/project.pbxproj +++ b/ios/VereignCredentialManager.xcodeproj/project.pbxproj @@ -89,6 +89,7 @@ ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; EDCB2B460766460B81E66726 /* FontAwesome5_Solid.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Solid.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf"; sourceTree = "<group>"; }; EF7CF2CD60574ADD8E0AFAD9 /* TitilliumWeb-SemiBold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "TitilliumWeb-SemiBold.ttf"; path = "../src/assets/fonts/TitilliumWeb-SemiBold.ttf"; sourceTree = "<group>"; }; + FB0F03C52BA33CA0009B97B1 /* VereignCredentialManager.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = VereignCredentialManager.entitlements; path = VereignCredentialManager/VereignCredentialManager.entitlements; sourceTree = "<group>"; }; FB1934E62AEAAE9F00138B0E /* MailCore.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = MailCore.xcframework; sourceTree = "<group>"; }; FB82ADE32AE7C8F200767A3B /* VereignImapModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VereignImapModule.m; sourceTree = "<group>"; }; FB82ADE52AE7C91600767A3B /* VereignImapModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VereignImapModule.h; sourceTree = "<group>"; }; @@ -138,6 +139,7 @@ 13B07FAE1A68108700A75B9A /* VereignCredentialManager */ = { isa = PBXGroup; children = ( + FB0F03C52BA33CA0009B97B1 /* VereignCredentialManager.entitlements */, FB82ADE22AE7C8C700767A3B /* VereignImapModule */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.mm */, @@ -588,6 +590,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = VereignCredentialManager/VereignCredentialManager.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 11; @@ -648,6 +651,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = VereignCredentialManager/VereignCredentialManager.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 11; @@ -794,7 +798,8 @@ "-ld_classic", "-Wl", "-ld_classic", - "-Wl -ld_classic ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -891,7 +896,8 @@ "-ld_classic", "-Wl", "-ld_classic", - "-Wl -ld_classic ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/ios/VereignCredentialManager/AppDelegate.mm b/ios/VereignCredentialManager/AppDelegate.mm index e82e049..a26cf67 100644 --- a/ios/VereignCredentialManager/AppDelegate.mm +++ b/ios/VereignCredentialManager/AppDelegate.mm @@ -42,4 +42,12 @@ return [RCTLinkingManager application:application openURL:url options:options]; } +- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity + restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler +{ + return [RCTLinkingManager application:application + continueUserActivity:userActivity + restorationHandler:restorationHandler]; +} + @end diff --git a/ios/VereignCredentialManager/VereignCredentialManager.entitlements b/ios/VereignCredentialManager/VereignCredentialManager.entitlements new file mode 100644 index 0000000..c3bffe0 --- /dev/null +++ b/ios/VereignCredentialManager/VereignCredentialManager.entitlements @@ -0,0 +1,12 @@ +<?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>com.apple.developer.associated-domains</key> + <array> + <string>applinks:holder-dev.vereign.com</string> + <string>applinks:issuer-dev.vereign.com</string> + <string>applinks:agent.hinpoc.ch</string> + </array> +</dict> +</plist> diff --git a/src/navigators/RootStack.tsx b/src/navigators/RootStack.tsx index fa1f87e..a1d9dda 100644 --- a/src/navigators/RootStack.tsx +++ b/src/navigators/RootStack.tsx @@ -9,10 +9,12 @@ import MainStack from './MainStack'; import OnboardingStack from './OnboardingStack'; import {useRealm} from "@realm/react"; import notifee, { EventType } from '@notifee/react-native'; -import {Screens, TabStacks} from 'src/type/navigators'; +import {Screens, TabStackParams, TabStacks} from 'src/type/navigators'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { ro } from 'date-fns/locale'; const RootStack: React.FC = observer(() => { - const navigation = useNavigation(); + const navigation = useNavigation<StackNavigationProp<TabStackParams>>(); const realm = useRealm(); useEffect(() => { rootStore.agentStore.createAgent(); @@ -23,21 +25,45 @@ const RootStack: React.FC = observer(() => { notifee.requestPermission(); }, []); + const handleDeepLinking = (url: string) => { + rootStore.urlStore.setDeepLink(url); + if (rootStore.authenticated) { + rootStore.urlStore.processDeepLinkIfAny(); + } + }; + + //if the app is not opened useEffect(() => { (async () => { - const handleDeepLinking = (url: string) => { - rootStore.urlStore.setDeepLink(url); - }; - - Linking.addEventListener('url', ({ url }) => handleDeepLinking(url)); const initialUrl = await Linking.getInitialURL(); - if (initialUrl) { - handleDeepLinking(initialUrl); + + if(initialUrl) { + const supported = await Linking.canOpenURL(initialUrl); + + if(supported) { + handleDeepLinking(initialUrl); + } } })(); }, []); + //if the app is opened in the background + useEffect(() => { + Linking.addEventListener('url', async ({url}) => { + if(url){ + const supported = await Linking.canOpenURL(url); + + if(supported) { + handleDeepLinking(url); + } + } + }); + return () => { + Linking.removeAllListeners('url'); + } + }, []); + // Subscribe to events useEffect(() => { if (!rootStore.authenticated) return; @@ -51,7 +77,7 @@ const RootStack: React.FC = observer(() => { if (realmId) { navigation.navigate(TabStacks.EmailStack, { screen: Screens.EmailDetails, - params: { realmId: realmId }, + params: { realmId: realmId}, }); } } @@ -67,7 +93,6 @@ const RootStack: React.FC = observer(() => { } }, [rootStore.authenticated]); - return rootStore.agentStore.agentCreated && rootStore.authenticated ? ( <UserInactivity isActive={rootStore.agentStore.active} -- GitLab