[INJIMOB-3181] - Add Deeplink support for iOS (#1907)

* [INJIMOB-3181]: add deep link support for ios

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: add deep link support for ios

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: add deep link support for ios

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: show popup for qrlogin when inital setup of app is incomplete

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: show popup for qrlogin when inital setup of app is incomplete

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: refactor deep link flow for future features

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: refactor deep link flow for future features

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: update locales for no shareable VCs

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: refactor auth selector

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

* [INJIMOB-3181]: refactor deeplink native modules

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>

---------

Signed-off-by: adityankannan-tw <adityan.kannan@thoughtworks.com>
This commit is contained in:
adityankannan-tw
2025-04-25 19:12:30 +05:30
committed by GitHub
parent 7d7671075a
commit 858343a7c9
14 changed files with 200 additions and 11 deletions

View File

@@ -13,6 +13,9 @@
1E6875E92CA554E80086D870 /* OpenID4VP in Frameworks */ = {isa = PBXBuildFile; productRef = 1E6875E82CA554E80086D870 /* OpenID4VP */; };
1E6875EB2CA554FD0086D870 /* RNOpenID4VPModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E6875EA2CA554FD0086D870 /* RNOpenID4VPModule.m */; };
1E6875ED2CA5550F0086D870 /* RNOpenID4VPModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E6875EC2CA5550F0086D870 /* RNOpenID4VPModule.swift */; };
1EED69F92DA913D30042EAFC /* IntentData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EED69F82DA913D30042EAFC /* IntentData.swift */; };
1EED69FB2DA914130042EAFC /* RNDeepLinkIntentModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EED69FA2DA914130042EAFC /* RNDeepLinkIntentModule.swift */; };
1EED69FD2DA914D00042EAFC /* RNDeepLinkIntentModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EED69FC2DA914D00042EAFC /* RNDeepLinkIntentModule.m */; };
34873E472CD8DAF3004DE734 /* VCIClient in Frameworks */ = {isa = PBXBuildFile; productRef = 34873E462CD8DAF3004DE734 /* VCIClient */; };
34873E4D2CD8DD11004DE734 /* pixelpass in Frameworks */ = {isa = PBXBuildFile; productRef = 34873E4C2CD8DD11004DE734 /* pixelpass */; };
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
@@ -68,6 +71,9 @@
1D23B9CD47CFD7F3C87D202F /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = Inji/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
1E6875EA2CA554FD0086D870 /* RNOpenID4VPModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNOpenID4VPModule.m; sourceTree = "<group>"; };
1E6875EC2CA5550F0086D870 /* RNOpenID4VPModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNOpenID4VPModule.swift; sourceTree = "<group>"; };
1EED69F82DA913D30042EAFC /* IntentData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentData.swift; sourceTree = "<group>"; };
1EED69FA2DA914130042EAFC /* RNDeepLinkIntentModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNDeepLinkIntentModule.swift; sourceTree = "<group>"; };
1EED69FC2DA914D00042EAFC /* RNDeepLinkIntentModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNDeepLinkIntentModule.m; sourceTree = "<group>"; };
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Inji.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Inji.a"; sourceTree = BUILT_PRODUCTS_DIR; };
6C2E3173556A471DD304B334 /* Pods-Inji.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Inji.debug.xcconfig"; path = "Target Support Files/Pods-Inji/Pods-Inji.debug.xcconfig"; sourceTree = "<group>"; };
7A4D352CD337FB3A3BF06240 /* Pods-Inji.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Inji.release.xcconfig"; path = "Target Support Files/Pods-Inji/Pods-Inji.release.xcconfig"; sourceTree = "<group>"; };
@@ -155,6 +161,9 @@
1E6875EA2CA554FD0086D870 /* RNOpenID4VPModule.m */,
1E6875EC2CA5550F0086D870 /* RNOpenID4VPModule.swift */,
1D23B9CD47CFD7F3C87D202F /* PrivacyInfo.xcprivacy */,
1EED69F82DA913D30042EAFC /* IntentData.swift */,
1EED69FA2DA914130042EAFC /* RNDeepLinkIntentModule.swift */,
1EED69FC2DA914D00042EAFC /* RNDeepLinkIntentModule.m */,
);
name = Inji;
sourceTree = "<group>";
@@ -541,6 +550,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1EED69FD2DA914D00042EAFC /* RNDeepLinkIntentModule.m in Sources */,
1E6875ED2CA5550F0086D870 /* RNOpenID4VPModule.swift in Sources */,
9C48504F2C3E59B5002ECBD5 /* RNVersionModule.swift in Sources */,
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
@@ -551,11 +561,13 @@
9C4850532C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
9C4850502C3E59B5002ECBD5 /* RNEventMapper.swift in Sources */,
1EED69FB2DA914130042EAFC /* RNDeepLinkIntentModule.swift in Sources */,
9C7CDF432C7CC13500243A9A /* RNSecureKeystoreModule.m in Sources */,
E86208172C0335EC007C3E24 /* RNVCIClientModule.m in Sources */,
9C48504E2C3E59B5002ECBD5 /* RNEventEmitter.swift in Sources */,
9C7CDF3E2C7CBEDE00243A9A /* RNSecureKeystoreModule.swift in Sources */,
9C48504B2C3E59B5002ECBD5 /* RNWalletModule.swift in Sources */,
1EED69F92DA913D30042EAFC /* IntentData.swift in Sources */,
9C48504D2C3E59B5002ECBD5 /* RNWalletModule.m in Sources */,
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */,
9C4850512C3E59B5002ECBD5 /* RNVersionModule.m in Sources */,

View File

@@ -3,8 +3,17 @@
#import <React/RCTBundleURLProvider.h>
#import <React/RCTLinkingManager.h>
#import <ExpoModulesCore-Swift.h>
#import "Inji-Swift.h"
@implementation AppDelegate
typedef NS_ENUM(NSInteger, URLScheme) {
URLSchemeInji,
URLSchemeOpenID4VP,
URLSchemeUnknown
};
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"main";
@@ -42,9 +51,36 @@
// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
[self handleIntent:url];
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
}
- (void)handleIntent:(NSURL *)url {
URLScheme scheme = [self schemeFromURL:url];
IntentData *intentData = [IntentData shared];
switch (scheme) {
case URLSchemeInji:
[intentData setQrData:url.absoluteString];
break;
case URLSchemeOpenID4VP:
[intentData setOvpQrData:url.absoluteString];
break;
case URLSchemeUnknown:
break;
}
}
- (URLScheme)schemeFromURL:(NSURL *)url {
if ([url.scheme isEqualToString:@"io.mosip.residentapp.inji"]) {
return URLSchemeInji;
} else if ([url.scheme isEqualToString:@"openid4vp"]) {
return URLSchemeOpenID4VP;
}
return URLSchemeUnknown;
}
// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];

View File

@@ -28,6 +28,12 @@
<string>io.mosip.residentapp</string>
</array>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>io.mosip.residentapp.inji</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>

63
ios/IntentData.swift Normal file
View File

@@ -0,0 +1,63 @@
import Foundation
@objc public class IntentData: NSObject {
@objc public static let shared = IntentData()
private let syncQueue = DispatchQueue(label: "com.intentdata.syncQueue", attributes: .concurrent)
private var qrData: String = ""
private var ovpQrData: String = ""
private override init() {
super.init()
}
@objc public func getQrData() -> String {
var data: String = ""
syncQueue.sync {
data = qrData
}
return data
}
@objc public func setQrData(_ newValue: String) {
syncQueue.async(flags: .barrier) {
self.qrData = newValue
}
}
@objc public func getOvpQrData() -> String {
var data: String = ""
syncQueue.sync {
data = ovpQrData
}
return data
}
@objc public func setOvpQrData(_ newValue: String) {
syncQueue.async(flags: .barrier) {
self.ovpQrData = newValue
}
}
func getDataByFlow(_ flowType: String?) -> String {
switch flowType {
case "qrLoginFlow":
return getQrData()
case "ovpFlow":
return getOvpQrData()
default:
return ""
}
}
func resetDataByFlow(_ flowType: String) {
switch flowType {
case "qrLoginFlow":
setQrData("")
case "ovpFlow":
setOvpQrData("")
default:
break
}
}
}

View File

@@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(DeepLinkIntent,NSObject)
RCT_EXTERN_METHOD(getDeepLinkIntentData:(NSString *)flowType resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(resetDeepLinkIntentData:(NSString *)flowType)
@end

View File

@@ -0,0 +1,24 @@
import Foundation
import React
@objc(DeepLinkIntent)
class RNDeepLinkIntentModule: NSObject, RCTBridgeModule {
static func moduleName() -> String {
return "DeepLinkIntent"
}
@objc func getDeepLinkIntentData(_ flowType: String, resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
let intentData = IntentData.shared
let result = intentData.getDataByFlow(flowType)
resolve(result)
}
@objc func resetDeepLinkIntentData(_ flowType: String) {
IntentData.shared.resetDataByFlow(flowType)
}
@objc static func requiresMainQueueSetup() -> Bool {
return false
}
}