Skip to content

Commit

Permalink
Generate android manifest in prebuild step (#12)
Browse files Browse the repository at this point in the history
* Install expo-build-properties plugin

* Move permissions into app.json

* Re-generate android folder

* Remove unrelated Detox test

* Lift keystore ignore pattern to root

* Add reusable gradle code snippets

* Move app config from JSON to JS

* Add plugin to customize gradle config

* Add changes to tracking before removing altogether

* Adjust linting config

* Switch config based on environment

* Convert app config to TS

* Add instructions for detox tests

* Remove committed debug keystore
  • Loading branch information
NSeydoux authored Aug 8, 2024
1 parent fab98b9 commit 34365de
Show file tree
Hide file tree
Showing 20 changed files with 338 additions and 231 deletions.
13 changes: 8 additions & 5 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
EXPO_PUBLIC_LOGIN_URL=https://datawallet.dev.inrupt.com/oauth2/authorization/wallet-app
EXPO_PUBLIC_WALLET_API=https://datawallet.dev.inrupt.com
TEST_ACCOUNT_USERNAME=
TEST_ACCOUNT_PASSWORD=
IOS_BINARY_PATH=
TEST_IOS_SIM=
TEST_ANDROID_EMU=
TEST_ACCOUNT_USERNAME=<Wallet Pod username>
TEST_ACCOUNT_PASSWORD=<Wallet Pod password>
IOS_BINARY_PATH=<Path to the built iOS binary>
TEST_IOS_SIM=<Name of the iOS simulator on your device>
# The following should align with a device emulator in Android Studio,
# e.g. 'Android_34' or 'Pixel_3a_API_34'
TEST_ANDROID_EMU=<Name of the Android emulator on your device>
SIGNING_CONFIG_PATH=/absolute/path/to/android-config/signing-config.gradle
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ module.exports = {
argsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-var-requires": [
"error", {
// These exceptions cover imports from CJS configuration modules (e.g. app.config.js, plugins/*.js)
allow: ["plugins", "fs"]
}
],
"import/prefer-default-export": "off",
"no-console": "off",
},
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ expo-env.d.ts
# @end expo-cli

.env

*.keystore
43 changes: 18 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ WALLET_UPLOAD_KEY_ALIAS=wallet
WALLET_UPLOAD_KEY_PASSWORD=<keystore password>
```

## Running
## Running the application

If you are going to run the application in an emulator or simulator, you need to build the development version using
one of the following:
Expand All @@ -94,31 +94,17 @@ In the output, you'll find options to open the app in a
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
### Configure test environment
Note: When running on the android emulator, there is a special loopback IP, 10.0.2.2, which points to the host machine 127.0.0.1. You can use it if the emulator complains about cleartext communication to the local network IP of the host.
The tests require access credentials for a Pod which will be used by this instance of the wallet.
Update your .env file with the following environment variables:
```bash
TEST_ACCOUNT_USERNAME=<Wallet Pod username>
TEST_ACCOUNT_PASSWORD=<Wallet Pod password>
IOS_BINARY_PATH=<Path to the built iOS binary>
TEST_IOS_SIM=<Name of the iOS simulator on your device>
ANDROID_BINARY_PATH=<Path to the main Android binary>
ANDROID_TEST_BINARY_PATH=<Path to the test Android binary>
TEST_ANDROID_EMU=<Name of the Android emulator on your device>
```
Replace placeholders with actual values specific to your setup.
## Running the UI-based tests
For Android development, ensure that the `TEST_ANDROID_EMU` configuration aligns with
a device emulator in Android Studio, e.g.:
```bash
TEST_ANDROID_EMU=Android_34
```
### Configure test environment
### Test native versions
The tests require access credentials for a Pod which will be used by this instance of the wallet.
Make a copy of the provided `.env.sample` named `.env`, and replace placeholders with actual values
specific to your setup.
#### iOS app
#### Running the tests on iOS
To build the iOS wallet app in an iOS simulator, just run the following command:
Expand Down Expand Up @@ -148,18 +134,25 @@ Execute the command below to start Detox test on iOS.
npx detox test --configuration=ios.sim.release
```
#### Android app
#### Running the tests on Android
Ensure that a virtual device has been added to the Android emulator.
First, you'll need to generate the app metadata with the following command:

```bash
npx expo prebuild --platform android
```

Run the following command to build the Android app. This process may take up to 30 minutes to complete.

```bash
npx detox build --configuration android.emu.release
```

For local development (a back-end server running on localhost or at an alternative location), use
the `android.emu.debug` configuration.
the `android.emu.debug` configuration. If running the debug configuration, make sure to run the
development server (`npx expo start`).

Once built, run the detox tests for the relevant configuration:

Expand Down Expand Up @@ -204,4 +197,4 @@ From here, the user can view all the requests along with their details (requesto
This page shows what access has been granted to other agents.
For each authorized agent, there is a list of the wallet resources to which they have access. Users also have the option to revoke access to each resource from this page.
For each authorized agent, there is a list of the wallet resources to which they have access. Users also have the option to revoke access to each resource from this page.
4 changes: 4 additions & 0 deletions android-config/extend-build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
if(project.hasProperty("inrupt.wallet.frontend.signing")
&& new File(project.property("inrupt.wallet.frontend.signing")).exists()) {
apply from: project.property("inrupt.wallet.frontend.signing");
}
18 changes: 18 additions & 0 deletions android-config/signing-config.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
android {
signingConfigs {
release {
if (project.hasProperty('WALLET_UPLOAD_STORE_FILE')) {
storeFile file(WALLET_UPLOAD_STORE_FILE)
storePassword WALLET_UPLOAD_STORE_PASSWORD
keyAlias WALLET_UPLOAD_KEY_ALIAS
keyPassword WALLET_UPLOAD_KEY_PASSWORD
}
}
}

buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
3 changes: 0 additions & 3 deletions android/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,3 @@ local.properties

# Bundle artifacts
*.jsbundle

# Keystores
*.keystore
37 changes: 22 additions & 15 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,36 +85,39 @@ android {

namespace 'com.inrupt.wallet'
defaultConfig {
// detox-plugin-default-config
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
applicationId 'com.inrupt.wallet'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0.0"
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
signingConfigs {
release {
if (project.hasProperty('WALLET_UPLOAD_STORE_FILE')) {
storeFile file(WALLET_UPLOAD_STORE_FILE)
storePassword WALLET_UPLOAD_STORE_PASSWORD
keyAlias WALLET_UPLOAD_KEY_ALIAS
keyPassword WALLET_UPLOAD_KEY_PASSWORD
}
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.release
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.release
signingConfig signingConfigs.debug
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
// Detox-specific additions to pro-guard
def detoxProguardRulesPath = new File(["node", "--print", "require.resolve('detox/package.json')"].execute(null, rootDir).text.trim(), "../android/detox/proguard-rules-app.pro")
proguardFile(detoxProguardRulesPath)

crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
}
}
packagingOptions {
Expand Down Expand Up @@ -145,11 +148,10 @@ android {
}

dependencies {
// The version of react-native is set by the React Native Gradle Plugin
androidTestImplementation('com.wix:detox:+')
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
implementation fileTree(dir: "libs", include: ["*.jar"])

def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
Expand Down Expand Up @@ -178,3 +180,8 @@ dependencies {

apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
applyNativeModulesAppBuildGradle(project)

if(project.hasProperty("inrupt.wallet.frontend.signing")
&& new File(project.property("inrupt.wallet.frontend.signing")).exists()) {
apply from: project.property("inrupt.wallet.frontend.signing");
}
28 changes: 0 additions & 28 deletions android/app/src/androidTest/java/com/inrupt/wallet/DetoxTest.kt

This file was deleted.

11 changes: 7 additions & 4 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"/>
</intent>
</queries>
<application 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">
<application 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" android:networkSecurityConfig="@xml/network_security_config">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
<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"/>
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait" android:networkSecurityConfig="@xml/network_security_config">
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
Expand All @@ -23,11 +26,11 @@
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="myapp"/>
<data android:scheme="inrupt-wallet"/>
<data android:scheme="com.inrupt.wallet"/>
<data android:scheme="exp+inrupt-wallet-frontend"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
</application>
</manifest>
</manifest>
5 changes: 3 additions & 2 deletions android/app/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>

<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.4.5.2</domain>
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">10.0.2.2</domain><domain includeSubdomains="true">localhost</domain>
</domain-config>

</network-security-config>
9 changes: 6 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ buildscript {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath('com.android.tools.build:gradle')
classpath('com.facebook.react:react-native-gradle-plugin')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
}
}

Expand All @@ -37,10 +38,12 @@ allprojects {
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
maven { url("$rootDir/../node_modules/detox/Detox-android")}
}
}
// @generated begin expo-camera-import - expo prebuild (DO NOT MODIFY) sync-f244f4f3d8bf7229102e8f992b525b8602c74770
def expoCameraMavenPath = new File(["node", "--print", "require.resolve('expo-camera/package.json')"].execute(null, rootDir).text.trim(), "../android/maven")
allprojects { repositories { maven { url(expoCameraMavenPath) } } }
// @generated end expo-camera-import
// @generated end expo-camera-import// @generated begin detox-import - expo prebuild (DO NOT MODIFY) sync-1c7ed0e9d1c19e4a2b5b79bb7ec877ac879fce8d
def detoxMavenPath = new File(["node", "--print", "require.resolve('detox/package.json')"].execute(null, rootDir).text.trim(), "../Detox-android")
allprojects { repositories { maven { url(detoxMavenPath) } } }
// @generated end detox-import
11 changes: 8 additions & 3 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
Expand All @@ -25,6 +25,9 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true

# Enable AAPT2 PNG crunching
android.enablePngCrunchInReleaseBuilds=true

# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64
Expand Down Expand Up @@ -55,5 +58,7 @@ EX_DEV_CLIENT_NETWORK_INSPECTOR=true
# Use legacy packaging to compress native libraries in the resulting APK.
expo.useLegacyPackaging=false

org.gradle.parallel=true
org.gradle.workers.max=4
# Path to the signing configuration gradle snippet
inrupt.wallet.frontend.signing=/home/nseydoux/dev/inrupt/profesional-services/inrupt-wallet-frontend/android-config/signing-config.gradle
android.extraMavenRepos=[]
android.kotlinVersion=1.8.22
Loading

0 comments on commit 34365de

Please sign in to comment.