-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ODK integration using Android intents (#1252)
* feat: init ODK integration via intent Signed-off-by: Paolo Miguel de Leon <[email protected]> * fix: sending data to ODK does not finish share flow properly Signed-off-by: Paolo Miguel de Leon <[email protected]> * feat: add error handlers to ODK module Signed-off-by: Paolo Miguel de Leon <[email protected]> * fix: building on Windows fails due duplicate libs from dependencies Signed-off-by: Paolo Miguel de Leon <[email protected]> * chore: cleanup logs Signed-off-by: Paolo Miguel de Leon <[email protected]> * refactor: move strings to const Signed-off-by: Paolo Miguel de Leon <[email protected]> --------- Signed-off-by: Paolo Miguel de Leon <[email protected]>
- Loading branch information
Showing
11 changed files
with
281 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,61 @@ | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.mosip.residentapp" xmlns:tools="http://schemas.android.com/tools"> | ||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28"/> | ||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/> | ||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> | ||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> | ||
<uses-permission android:name="android.permission.BLUETOOTH"/> | ||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> | ||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/> | ||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> | ||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/> | ||
<uses-permission android:name="android.permission.CAMERA"/> | ||
<uses-permission android:name="android.permission.INTERNET"/> | ||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/> | ||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> | ||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||
<uses-permission android:name="android.permission.USE_BIOMETRIC"/> | ||
<uses-permission android:name="android.permission.USE_FINGERPRINT"/> | ||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.mosip.residentapp" | ||
xmlns:tools="http://schemas.android.com/tools"> | ||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" | ||
android:maxSdkVersion="28" /> | ||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> | ||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> | ||
<uses-permission android:name="android.permission.BLUETOOTH" /> | ||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> | ||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> | ||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> | ||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" | ||
android:usesPermissionFlags="neverForLocation" /> | ||
<uses-permission android:name="android.permission.CAMERA" /> | ||
<uses-permission android:name="android.permission.INTERNET" /> | ||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> | ||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> | ||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | ||
<uses-permission android:name="android.permission.USE_BIOMETRIC" /> | ||
<uses-permission android:name="android.permission.USE_FINGERPRINT" /> | ||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||
<queries> | ||
<intent> | ||
<action android:name="android.intent.action.VIEW"/> | ||
<category android:name="android.intent.category.BROWSABLE"/> | ||
<data android:scheme="https"/> | ||
<action android:name="android.intent.action.VIEW" /> | ||
<category android:name="android.intent.category.BROWSABLE" /> | ||
<data android:scheme="https" /> | ||
</intent> | ||
</queries> | ||
<application tools:replace="usesCleartextTraffic" android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:usesCleartextTraffic="false"> | ||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/> | ||
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="48.0.0"/> | ||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/> | ||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/> | ||
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@anonymous/inji"/> | ||
<activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|locale|layoutDirection" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait"> | ||
<application tools:replace="usesCleartextTraffic" android:name=".MainApplication" | ||
android:label="@string/app_name" android:icon="@mipmap/ic_launcher" | ||
android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" | ||
android:theme="@style/AppTheme" android:usesCleartextTraffic="false"> | ||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true" /> | ||
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="48.0.0" /> | ||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" | ||
android:value="ALWAYS" /> | ||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0" /> | ||
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" | ||
android:value="https://exp.host/@anonymous/inji" /> | ||
<activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" | ||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|locale|layoutDirection" | ||
android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" | ||
android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN"/> | ||
<category android:name="android.intent.category.LAUNCHER"/> | ||
<action android:name="android.intent.action.MAIN" /> | ||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
<intent-filter> | ||
<action android:name="android.intent.action.VIEW"/> | ||
<category android:name="android.intent.category.DEFAULT"/> | ||
<category android:name="android.intent.category.BROWSABLE"/> | ||
<data android:scheme="io.mosip.residentapp"/> | ||
<action android:name="android.intent.action.VIEW" /> | ||
<category android:name="android.intent.category.DEFAULT" /> | ||
<category android:name="android.intent.category.BROWSABLE" /> | ||
<data android:scheme="io.mosip.residentapp" /> | ||
</intent-filter> | ||
<intent-filter> | ||
<action android:name="io.mosip.residentapp.odk.REQUEST" /> | ||
<category android:name="android.intent.category.DEFAULT" /> | ||
</intent-filter> | ||
</activity> | ||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/> | ||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> | ||
</application> | ||
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
android/app/src/main/java/io/mosip/residentapp/ODKIntentModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package io.mosip.residentapp; | ||
|
||
import android.app.Activity; | ||
import android.content.Intent; | ||
import android.os.Bundle; | ||
|
||
import com.facebook.react.bridge.Arguments; | ||
import com.facebook.react.bridge.Promise; | ||
import com.facebook.react.bridge.ReactApplicationContext; | ||
import com.facebook.react.bridge.ReactContextBaseJavaModule; | ||
import com.facebook.react.bridge.ReactMethod; | ||
import com.facebook.react.bridge.ReadableMap; | ||
|
||
public class ODKIntentModule extends ReactContextBaseJavaModule { | ||
|
||
private static final String MODULE_NAME = "ODKIntentModule"; | ||
|
||
/** | ||
* The action to check for sending data to ODK Collect. Use this when configuring the ODK form. | ||
*/ | ||
private static final String ODK_REQUEST_ACTION = "io.mosip.residentapp.odk.REQUEST"; | ||
|
||
@Override | ||
public String getName() { | ||
return MODULE_NAME; | ||
} | ||
|
||
ODKIntentModule(ReactApplicationContext context) { | ||
super(context); | ||
} | ||
|
||
@ReactMethod | ||
public void isRequestIntent(Promise promise) { | ||
try { | ||
Activity activity = getCurrentActivity(); | ||
Intent intent = activity.getIntent(); | ||
String action = intent.getAction(); | ||
if (activity == null || intent == null || action == null) { | ||
promise.resolve(false); | ||
return; | ||
} | ||
|
||
promise.resolve(action.equals(ODK_REQUEST_ACTION)); | ||
|
||
} catch (Exception e) { | ||
promise.reject("E_UNKNOWN", e.getMessage()); | ||
} | ||
} | ||
|
||
@ReactMethod | ||
public void sendBundleResult(ReadableMap vcData) { | ||
try { | ||
Activity activity = getCurrentActivity(); | ||
if (activity == null) { | ||
throw new Exception("Activity does not exist"); | ||
} | ||
|
||
Intent result = new Intent(); | ||
result.setPackage(activity.getPackageName()); | ||
|
||
Bundle vcBundle = new Bundle(Arguments.toBundle(vcData)); | ||
if (vcBundle == null) { | ||
throw new Exception("Bundle could not be created"); | ||
} | ||
|
||
for (String key : vcBundle.keySet()) { | ||
result.putExtra(key, vcBundle.getString(key)); | ||
} | ||
|
||
activity.setResult(Activity.RESULT_OK, result); | ||
activity.finish(); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
android/app/src/main/java/io/mosip/residentapp/ODKIntentPackage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package io.mosip.residentapp; | ||
|
||
import com.facebook.react.ReactPackage; | ||
import com.facebook.react.bridge.NativeModule; | ||
import com.facebook.react.bridge.ReactApplicationContext; | ||
import com.facebook.react.uimanager.ViewManager; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class ODKIntentPackage implements ReactPackage { | ||
|
||
@Override | ||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
@Override | ||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { | ||
List<NativeModule> modules = new ArrayList<>(); | ||
|
||
modules.add(new ODKIntentModule(reactContext)); | ||
|
||
return modules; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import {NativeModules} from 'react-native'; | ||
|
||
const {ODKIntentModule} = NativeModules; | ||
|
||
export enum ODKIntentVcField { | ||
UIN = 'uin', | ||
FullName = 'full_name', | ||
DateOfBirth = 'date_of_birth', | ||
Email = 'email', | ||
Phone = 'phone', | ||
Biometrics = 'biometrics', | ||
Issuer = 'issuer', | ||
IssuanceDate = 'issuance_date', | ||
} | ||
|
||
export type ODKIntentVcData = Partial<Record<ODKIntentVcField, string>>; | ||
interface ODKIntentInterface { | ||
isRequestIntent: () => Promise<boolean>; | ||
sendBundleResult: (vcData: ODKIntentVcData) => void; | ||
} | ||
|
||
export default ODKIntentModule as ODKIntentInterface; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.