twilio / twilio-voice-react-native

Other
73 stars 27 forks source link

Android Application crashes everytime when launch #433

Open ayazalphasquad opened 1 week ago

ayazalphasquad commented 1 week ago

Hi @mhuynh5757 ,

I need help configuring this package with the android updated SDK API level 34. I followed all the steps outlined in the reference application, but I'm unable to run the app. It crashes every time we try to open it.

If we don't configure the application then I get the below error:

----- Error Start------ Attempt to read from field 'come.twiliovoicereactnative.JSEventEmitter com.twiliovoicereactnative.VoiceApplicationProxy.JSEventEmiiter" on a null object reference in the method com.twiliovoicereactnative.JSEventEmittercom.twiliovoicereactnative.VoiceApplicationProxy.get.JSEventEmitter() -----Error End-------

I've used the same JNI libraries from the reference application and configured them in the build.gradle file, but it hasn't resolved the issue.

Here is the code:

Files paths: android/app/src/main/java/com/sigmago/MainActivity.java android/app/src/main/java/com/sigmago/MainApplication.java android/app/src/main/java/com/sigmago/MainReactNativeHost.java android/app/src/main/java/com/sigmago/newarchitecture/MainApplicationReactNativeHost.java android/app/src/main/java/com/sigmago/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java android/app/src/main/java/com/sigmago/newarchitecture/components/MainComponentsRegistry.java android/app/src/main/java/com/sigmago/jni/CMakeLists.txt

package com.sigmago;

import android.Manifest; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.widget.Toast;

import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; import com.facebook.react.defaults.DefaultReactActivityDelegate; import com.twiliovoicereactnative.VoiceActivityProxy;

public class MainActivity extends ReactActivity {

public static class MainActivityDelegate extends ReactActivityDelegate { public MainActivityDelegate(ReactActivity activity, String mainComponentName) { super(activity, mainComponentName); }

@Override protected ReactRootView createRootView() { ReactRootView reactRootView = new ReactRootView(getContext()); // If you opted-in for the New Architecture, we enable the Fabric Renderer. reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); return reactRootView; }

@Override protected boolean isConcurrentRootEnabled() { // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18). // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; } }

private final VoiceActivityProxy activityProxy = new VoiceActivityProxy( this, permission -> { if (Manifest.permission.RECORD_AUDIO.equals(permission)) { Toast.makeText( MainActivity.this, "Microphone permissions needed. Please allow in your application settings.", Toast.LENGTH_LONG).show(); } else if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) && Manifest.permission.BLUETOOTH_CONNECT.equals(permission)) { Toast.makeText( MainActivity.this, "Bluetooth permissions needed. Please allow in your application settings.", Toast.LENGTH_LONG).show(); } else if ((Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) && Manifest.permission.POST_NOTIFICATIONS.equals(permission)) { Toast.makeText( MainActivity.this, "Notification permissions needed. Please allow in your application settings.", Toast.LENGTH_LONG).show(); } });

/**

Returns the name of the main component registered from JavaScript. This is used to schedule rendering of the component. */ @OverRide protected String getMainComponentName() { return "sigmagoMobileNebulaConnections"; } /**

Returns the instance of the {https://github.com/link ReactActivityDelegate}. Here we use a util class {https://github.com/link DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React (aka React 18) with two boolean flags. */ @OverRide protected ReactActivityDelegate createReactActivityDelegate() { return new DefaultReactActivityDelegate( this, getMainComponentName(), // If you opted-in for the New Architecture, we enable the Fabric Renderer. DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled ); } @OverRide protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); activityProxy.onCreate(savedInstanceState); }

@OverRide public void onDestroy() { activityProxy.onDestroy(); super.onDestroy(); }

@OverRide public void onNewIntent(Intent intent) { super.onNewIntent(intent); activityProxy.onNewIntent(intent); } }

MainApplication.java: package com.sigmago;

import android.app.Application;

import com.facebook.react.PackageList; import com.facebook.react.ReactApplication; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; import com.facebook.react.defaults.DefaultReactNativeHost; import com.facebook.soloader.SoLoader; import java.util.List;

import com.sigmago.newarchitecture.MainApplicationReactNativeHost; import com.twiliovoicereactnative.VoiceApplicationProxy; import com.twiliovoicereactnative.VoiceApplicationProxy.VoiceReactNativeHost;

import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; import android.os.Build; import org.jetbrains.annotations.Nullable; import android.content.Context;

public class MainApplication extends Application implements ReactApplication {

private final MainApplicationReactNativeHost mNewArchitectureNativeHost = new MainApplicationReactNativeHost(this);

private final VoiceApplicationProxy voiceApplicationProxy;

// Use VoiceReactNativeHost instead of ReactNativeHost private final VoiceReactNativeHost mVoiceReactNativeHost = new VoiceReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; }

    @Override
    protected List<ReactPackage> getPackages() {
        @SuppressWarnings("UnnecessaryLocalVariable")
        List<ReactPackage> packages = new PackageList(this).getPackages();
        // Add any packages here if needed
        return packages;
    }

    @Override
    protected String getJSMainModuleName() {
        return "index";
    }

};

public MainApplication() { voiceApplicationProxy = new VoiceApplicationProxy(mVoiceReactNativeHost); }

@Override public ReactNativeHost getReactNativeHost() { return mVoiceReactNativeHost; // Use the VoiceReactNativeHost }

@Override public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) { if (Build.VERSION.SDK_INT >= 34 && getApplicationInfo().targetSdkVersion >= 34) { return super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED); } else { return super.registerReceiver(receiver, filter); } }

@Override public void onCreate() { super.onCreate(); voiceApplicationProxy.onCreate(); SoLoader.init(this, / native exopackage / false); if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { DefaultNewArchitectureEntryPoint.load(); } com.sigmago.ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); }

@Override public void onTerminate() { voiceApplicationProxy.onTerminate(); super.onTerminate(); } }

package com.sigmago;

import android.app.Application; import com.facebook.react.PackageList; import com.facebook.react.ReactPackage; import com.twiliovoicereactnative.VoiceApplicationProxy; import java.util.List;

class MainReactNativeHost extends VoiceApplicationProxy.VoiceReactNativeHost { public MainReactNativeHost(Application application) { super(application); }

@Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; }

@Override protected List getPackages() { List packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here // packages.add(new MyReactNativePackage()); return packages; }

@Override protected String getJSMainModuleName() { return "index"; } }

MainComponentsRegistry.java: package com.sigmago.newarchitecture.components;

import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.react.fabric.ComponentFactory; import com.facebook.soloader.SoLoader;

/**

Class responsible to load the custom Fabric Components. This class has native methods and needs a corresponding C++ implementation/header file to work correctly (already placed inside the jni/ folder for you). Please note that this class is used ONLY if you opt-in for the New Architecture (see the

newArchEnabled property). Is ignored otherwise. */ @DoNotStrip public class MainComponentsRegistry { static { SoLoader.loadLibrary("fabricjni"); } @DoNotStrip private final HybridData mHybridData;

@DoNotStrip private native HybridData initHybrid(ComponentFactory componentFactory);

@DoNotStrip private MainComponentsRegistry(ComponentFactory componentFactory) { mHybridData = initHybrid(componentFactory); }

@DoNotStrip public static MainComponentsRegistry register(ComponentFactory componentFactory) { return new MainComponentsRegistry(componentFactory); } }

package com.sigmago.newarchitecture.modules;

import com.facebook.jni.HybridData; import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackageTurboModuleManagerDelegate; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.soloader.SoLoader; import java.util.List;

/**

Class responsible to load the TurboModules. This class has native methods and needs a corresponding C++ implementation/header file to work correctly (already placed inside the jni/ folder for you). Please note that this class is used ONLY if you opt-in for the New Architecture (see the

newArchEnabled property). Is ignored otherwise. */ public class MainApplicationTurboModuleManagerDelegate extends ReactPackageTurboModuleManagerDelegate { private static volatile boolean sIsSoLibraryLoaded;

protected MainApplicationTurboModuleManagerDelegate( ReactApplicationContext reactApplicationContext, List packages) { super(reactApplicationContext, packages); }

protected native HybridData initHybrid();

native boolean canCreateTurboModule(String moduleName);

public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { protected MainApplicationTurboModuleManagerDelegate build( ReactApplicationContext context, List packages) { return new MainApplicationTurboModuleManagerDelegate(context, packages); } }

@OverRide protected synchronized void maybeLoadOtherSoLibraries() { if (!sIsSoLibraryLoaded) { // If you change the name of your application .so file in the Android.mk file, // make sure you update the name here as well. SoLoader.loadLibrary("sigmago_appmodules"); // Updated library name according to the package name sIsSoLibraryLoaded = true; } } }

CMakeLists.txt cmake_minimum_required(VERSION 3.13)

Define the library name here. project(sigmago_appmodules)

This file includes all the necessary to let you build your application with the New Architecture. include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)

Android/app/build.gradle: Added the below condition after defaultConfig:

if (isNewArchitectureEnabled()) { // We configure the NDK build only if you decide to opt-in for the New Architecture. externalNativeBuild { cmake { path "$projectDir/src/main/jni/CMakeLists.txt" } } def reactAndroidProjectDir = project(':ReactAndroid').projectDir def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) { dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck") from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") into("$buildDir/react-ndk/exported") } def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) { dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck") from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") into("$buildDir/react-ndk/exported") } afterEvaluate { // If you wish to add a custom TurboModule or component locally, // you should uncomment this line. // preBuild.dependsOn("generateCodegenArtifactsFromSchema") preDebugBuild.dependsOn(packageReactNdkDebugLibs) preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)

    // Due to a bug inside AGP, we have to explicitly set a dependency
    // between configureCMakeDebug* tasks and the preBuild tasks.
    // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
    configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
    configureCMakeDebug.dependsOn(preDebugBuild)
    reactNativeArchitectures().each { architecture ->
        tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
            dependsOn("preDebugBuild")
        }
        tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
            dependsOn("preReleaseBuild")
        }
    }
}

Android/build.gradle:

buildToolsVersion = "34.0.0" minSdkVersion = 23 compileSdkVersion = 34 targetSdkVersion = 34

// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. ndkVersion = "23.1.7779620"

mhuynh5757 commented 22 hours ago

Hello @ayazalphasquad have you followed the steps outlined in this guide? https://github.com/twilio/twilio-voice-react-native/blob/main/docs/migration-guide-beta.4.md

For reference, you can also check our reference app (which I see that you've mentioned): https://github.com/twilio/twilio-voice-react-native-app/tree/main/app/android/app/src/main/java/com/twiliovoicereactnativereferenceapp

You'll need to modify your Java files to bootstrap the Android portion of this SDK.