React native custom buildType not using metro - react-native

I need to build the same app to different applicationIds so that I can publish it on the Play Store / App Store as private applications for some of the customers of my company.
I decided to use react-native-config, as it should allow me to change applicationId and some env variables easily.
I have created some .env.${variant} files, that is, in the following examples, .env.customer1.
I have set the needed buildTypes as follows:
...
buildTypes {
debug {
...
}
customer1 {
initWith debug
applicationIdSuffix "customer1"
}
}
I forced react.gradle not to bundle when building with these variants
project.ext.react [
bundleInCustomer1: false,
devDisabledInCustomer1: false
]
Then I use this command line to run on my physical device
copy .env.customer .env && react-native run-android --variant=customer1 --appIdSuffix 'customer1'
The result is that the app is built and launched on my device, but what I see is an old version of the app (probably the last one that I have built using assembleRelease, some weeks ago), metro getting launched but telling me this when I try to force a reload, otherwise telling me nothing
warn No apps connected. Sending "reload" ...
I tried without any success
gradlew clean
npm start --cache-reload
npm cache clean --forced
npm i
Building the app without any variant (thus using default debug) correctly works.

Thanks to this answer, I've succeeded in solving my issue.
Instead of using buildTypes now I'm using flavors.
So,
android {
...
flavorDimensions "standard"
defaultConfig {
applicationId "com.stackoverflow"
...
productFlavors {
customer1 {
applicationId "com.stackoverflow.customer1"
dimension "standard"
}
}
}
and launching via
react-native run-android --variant=customer1Debug --appIdSuffix 'customer1'

Related

The android device show "App isn't installed" after upgrade React Native 0.70.5

I upgraded my react-native project from 0.69.6 to 0.70.5
I run "npx react-native run-android" on my android device. It show "App isn't installed" when I click the app. If I go to device settings -> my app -> click "OPEN" button, then the app can run successfully. I can see the loading in bundle.
I have added applicationIdSuffix on android/app/build.grade. This setup always used.
buildTypes {
debug: {
applicationIdSuffix ".dev"
}
}
My AndroidManifest package is "com.companyname.xxxx.android"
May I know how to solve this issue? Thank you everyone.

Dynamically link packages based on product flavor to support GMS & HMS with one code base

In order for my application to be approved and visible on both of Google PlayStore and Huawei App Gallery, I am currently maintaining two different branches:
Google branch which has react-native-maps installed but no HMS packages.
Huawei branch which has HMS maps installed but not react-native-maps.
I'm aware of the HMS+GMS approach, but from my experience having a module like react-native-maps that relies heavily on GMS made my app hidden from pure HMS devices, even though my app had ways to check and never navigate to screens that rely on GMS.
Both branches have the same code on the JavaScript side except one file which is used to display the map, this file imports from react-native-maps on GMS phones, and from react-native-hms-map for Huawei phones.
My question is: is there a way to dynamically exclude some files and packages in build time based on the product flavor so that I can use one codebase and just ignore some file when building the APK.
Solution:
Managed to come up with a solution that got my app approved and fully visible on app stores through disabling auto linking for react native maps and manually linking it based on the product flavor.
(Code might not be the cleanest but it's behaving as expected, so any cleanup suggestions would be appreciated)
Steps:
1. Disable manual linking for react-native-maps on android
By creating a file named react-native.config.js in the root directory of the project, and added the following
module.exports = {
dependencies: {
"react-native-maps": {
platforms: {
android: null,
}
}
}
}
2. Added product flavors for Google and Huawei
By adding the following to android/app/build.gradle
...
...
android{
...
...
flavorDimensions "provider"
productFlavors {
google {
dimension "provider"
}
huawei {
dimension "provider"
}
}
...
...
}
...
...
3. Added the following to the same android/app/build.gradle file
...
...
dependencies {
...
...
huaweiImplementation 'com.huawei.hms:location:4.0.2.300'
huaweiImplementation 'com.huawei.hms:hwid:4.0.1.300'
googleImplementation project(':react-native-maps')
...
...
}
...
...
4. Added the following into android/settings.gradle
include ':react-native-maps'
project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/lib/android')
5. Created 2 folders inside android/app/src
folders named: huawei and google with the following structure
6. added a java file inside android/app/src/google/java/com/appname
MapPackageChecker.java
package com.appname;
import com.facebook.react.ReactPackage;
import com.airbnb.android.react.maps.MapsPackage;
public class MapPackageChecker {
public static ReactPackage getMapPackage() {
return new MapsPackage();
}
}
7. added a java file inside android/app/src/huawei/java/com/appname
MapPackageChecker.java
package com.appname;
import com.facebook.react.ReactPackage;
public class MapPackageChecker {
public static ReactPackage getMapPackage() {
return null;
}
}
8. added the following to android/app/src/main/java/com/appname/MainApplication.java
import static com.appname.MapPackageChecker.getMapPackage;
...
...
#Override
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
//start of new lines
if(BuildConfig.FLAVOR.equals("google")){
packages.add(getMapPackage());
}
//end of new lines
return packages;
}
...
...
9. Access flavor name from react native code
I decided to use react-native-build-config for this purpose
Example for navigation component:
import googleMapScreen from "./googleMapScreen.js"; //relies on gms maps
import huaweiMapScreen from "./huaweiMapScreen.js"; //relies on hms maps
import BuildConfig from 'react-native-build-config';
const flavor = BuildConfig.FLAVOR
...
...
<Stack.Screen
name="MapScreen"
component={flavor === "huawei" ? huaweiMapScreen : googleMapScreen}
/>
...
...
10. After adding product flavors, we need to make some changes to our commands
yarn react-native run-android
becomes: yarn react-native run-android --variant=huaweiDebug
or: yarn react-native run-android --variant=googleDebug
./gradlew assembleRelease
becomes: ./gradlew assembleHuaweiRelease
or: ./gradlew assembleGoogleRelease
11. For convenience we can add the following to package.json scripts
"scripts":{
"run-huawei": "yarn react-native run-android --variant=huaweiDebug",
"run-google": "yarn react-native run-android --variant=googleDebug",
}
First of all, Huawei does support react-native-maps. Please check here: https://developer.huawei.com/consumer/en/doc/development/HMS-Plugin-Guides-V1/integrating-sdk-0000001050034173-V1
When HMS+GMS is the preferred solution, in the code the APP needs to decide whether to use HMS or GMS based on the availability of HMS and GMS services on the device.
. How to decide whether to use HMS or GMS :
Check that GMS is available
There are also some links for your reference:
React Native Application Detect device support GMS or HMS: https://forums.developer.huawei.com/forumPortal/en/topic/0201200045194610058?fid=0101187876626530001
Choice SDK - an open-source GMS-HMS wrapper: https://forums.developer.huawei.com/forumPortal/en/topic/0201555879126330259?fid=0101187876626530001
You may refer to this.
It's configured in here:
And run the following command:

React Native: "A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade"

I created a new react native project and ran react-native run-android.
However, I am getting this error:
A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
Here's the screenshot:
Here's my android/build.gradle:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "29.0.2"
minSdkVersion = 16
compileSdkVersion = 29
targetSdkVersion = 29
}
repositories {
google()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:3.5.3")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
google()
jcenter()
maven { url 'https://www.jitpack.io' }
}
}
I am new with react native and this is a new project so any help will be appreciated.
Solution-1: The problem was resolved by deleting and re-creating the AVD (Android Virtual Device) file. The AVD can be deleted from Android Studio. It is usually saved at C:\Users\<userName>\.android\avd
Most likely, you also need to execute the following commands.
cd <project_filder>
cd android
gradlew clean
In case you did not notice the comments on the question (above), please check them out. They include more suggestions, which might be relevant to the problem.
1st Update:
Solution-2: In some other instance, in addition to deleting and re-creating the AVD, I had to do the following steps.
REM 1. Removing cache files
rd %localappdata%\Temp\metro-cache /s /q
del %localappdata%\Temp\haste-map*
REM 2. Cleaning Gradle files
cd <project_filder>
cd android & gradlew clean & cd ..
REM 3. Deleting node_modules
rd node_modules /q /s
REM 4. Cleaning npm cache
npm cache clean --force
REM 5. Re-installing npm modules
npm install
2nd Update:
Solution-3: In a 3rd instance, I had to add the following line in the file <proj-folder>/android/gradle.properties
org.gradle.jvmargs=-Xmx4608m
Worth noting I encountered this in a native (Kotlin) Android project.
For me this was caused by having densities specified in my resConfigs:
build.grade (:app)
developLint {
dimension "version"
resConfigs "en", "he-rIL", "iw-rIL", "xxhdpi"
}
(Note the "xxhdpi" above)
Removing the density solved the problem.

Flipper: Flipper Hermes debugger does not show

Flipper Hermes debugger does not show
I would like to ask how to make him display normally?
react-native:0.62.2 (Update from 0.61 to 0.62.2)
https://fbflipper.com/
https://reactnative.dev/docs/hermes
error message:
Metro is connected but no Hermes apps were found.
Open a React Native screen with Hermes enabled to connect. Note: you may need to reload the app in order to reconnect the device to Metro.
Following this in android/app/build.gradle file
project.ext.react = [
entryFile: "index.js",
enableHermes: true
]
And this in proguard-rules.pro file
-keep class com.facebook.hermes.unicode.** { *; }
-keep class com.facebook.jni.** { *; }
And
$ cd android && ./gradlew clean
Worked for me
In my case it was showing screen mentioned at https://github.com/facebook/flipper/issues/1520
I found out that it was happening due to company VPN. I disconnected the VPN whenever I had to debug and it worked normally.
Changing the below config in android/app/gradle.properties worked for me.
expo.jsEngine=hermes
And then cd android && ./gradlew clean
You can also verify if hermes is enabled by adding below snippet to App.js or any other .js file in react native.
const isHermes = () => !!global.HermesInternal;
console.log("Is Hermes enabled " + isHermes())

configuring transform-inline-environment-variables for react-native 0.60.6

module.exports = function () {
return {
"presets": ['module:metro-react-native-babel-preset'],
"plugins": [
["transform-inline-environment-variables", {
"include": [
"APP_ENV"
]
}]
]
}
};
This is my babel.config.js for my react-native project, and I'm trying to configure the transform-inline-environment-variables babel plugin. But whenever I run the app the environment variable is always undefined.
I run react-native start --reset-cache to clear the cache and run the project using the command APP_ENV=dev react-native run-ios.
But the variable is still undefined. What am I doing wrong here? The react-native version is 0.60.6
Try logging access directly (rather than destructuring):
console.log(process.env.APP_ENV)
Also, once you have the emulator connected, you can then run start, so:
yarn run-ios
Close the metro bundler terminal window and leave the emulator open
API_ENV=dev yarn start --reset-cache
This issue is covered in detail here.
Better still, replace your implementation with react-native-config.