How to create custom plugin in React Native? That should call native Java code asking for Camera and Recording permissions.
Creating a custom plugin in React Native to call native Java code, specifically for handling camera and recording permissions, involves several steps. You’ll need to set up both the JavaScript and native Android sides to communicate with each other. Below are the detailed steps for achieving this:
Step-by-Step Guide
1. Setting Up React Native Project
First, ensure you have a React Native project set up. If you don’t have one, you can create a new project using:
sudo npx react-native init MyProject
Run instructions for Android:
• Have an Android emulator running (quickest way to get started), or a device connected.
• cd "/Users/ankitmaheshwari/Data/React-Projects/POC/MyProject" && npx react-native run-android
Run instructions for iOS:
• cd "/Users/ankitmaheshwari/Data/React-Projects/POC/MyProject/ios"
• Install Cocoapods
• bundle install # you need to run this only once in your project.
• bundle exec pod install
• cd ..
• npx react-native run-ios
- or -
• Open MyProject/ios/MyProject.xcodeproj in Xcode or run "xed -b ios"
• Hit the Run button
2. Create a Custom Native Module in Android
A. Create Java Class for Native Module:
Navigate to your Android project directory and create a new Java class in android/app/src/main/java/com/yourprojectname/
.
cd android/app/src/main/java/com/yourprojectname/
mkdir custommodule
touch CustomModule.java
Edit the CustomModule.java
to create a basic native module:
package com.yourprojectname.custommodule;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
public class CustomModule extends ReactContextBaseJavaModule {
private static final int CAMERA_PERMISSION_CODE = 100;
private static final int RECORD_AUDIO_PERMISSION_CODE = 101;
CustomModule(ReactApplicationContext context) {
super(context);
}
@NonNull
@Override
public String getName() {
return "CustomModule";
}
@ReactMethod
public void checkPermissions(Promise promise) {
boolean cameraGranted = ContextCompat.checkSelfPermission(getReactApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
boolean recordAudioGranted = ContextCompat.checkSelfPermission(getReactApplicationContext(), Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
promise.resolve(cameraGranted && recordAudioGranted);
}
@ReactMethod
public void requestPermissions(Promise promise) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ActivityCompat.requestPermissions(getCurrentActivity(), new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, CAMERA_PERMISSION_CODE);
} else {
promise.resolve(true);
}
}
}
B. Register the Module:
Create a CustomPackage.java
to register your module:
sudo touch CustomPackage.java
Code inside CustomPackage.java
package com.yourprojectname.custommodule;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
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 CustomPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new CustomModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
C. Register Your Package in MainApplication.java
:
Edit android/app/src/main/java/com/yourprojectname/MainApplication.java
to include your new package:
import com.myproject.custommodule.CustomPackage;
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
packages.add(new CustomPackage());
return packages;
}
3. Create JavaScript Interface
A. Create a JS or TSX Module to Access the Native Code:
Create a new JavaScript file in your React Native project, for example, CustomModule.js
.
import { NativeModules } from 'react-native';
const { CustomModule } = NativeModules;
export const checkPermissions = () => {
return CustomModule.checkPermissions();
};
export const requestPermissions = () => {
return CustomModule.requestPermissions();
};
If you are using tsx version of React Native project use CustomModule.tsx
code as follows:
import { NativeModules } from 'react-native';
// Type definition for the `CustomModule` object
interface CustomModule {
checkPermissions(): Promise<boolean>; // Return type is a promise that resolves to a boolean
requestPermissions(): Promise<void>; // Return type is a promise that resolves to nothing (void)
}
// Cast the NativeModules.CustomModule to the typed interface
const CustomModule = NativeModules.CustomModule as CustomModule;
export const checkPermissions = (): Promise<boolean> => {
return CustomModule.checkPermissions();
};
export const requestPermissions = (): Promise<void> => {
return CustomModule.requestPermissions();
};
This is how I created under /src/modules/CustomModules.tsx
B. Use the Module in Your React Native Component:
You can now use this module in your React Native components. For instance, in App.tsx
:
import React, { useEffect } from 'react';
import { View, Button, Alert } from 'react-native';
import { checkPermissions, requestPermissions } from './CustomModule';
const App = () => {
useEffect(() => {
checkPermissions()
.then((granted: boolean) => {
if (!granted) {
Alert.alert('Permissions not granted', 'Camera and Audio permissions are required.');
}
});
}, []);
const requestCameraAndAudioPermissions = () => {
requestPermissions()
.then((granted: boolean) => {
if (granted) {
Alert.alert('Permissions granted', 'You can now access the camera and record audio.');
} else {
Alert.alert('Permissions not granted', 'Camera and Audio permissions are required.');
}
});
};
return (
<View>
<Button title="Request Permissions" onPress={requestCameraAndAudioPermissions} />
</View>
);
};
export default App;
C. Handling Permissions in Native Code
Make sure you handle the results of permission requests in your Java code. Here’s how you can handle it in MainActivity.java
:
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 100: // CAMERA_PERMISSION_CODE
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
} else {
// Permission denied
}
break;
case 101: // RECORD_AUDIO_PERMISSION_CODE
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
} else {
// Permission denied
}
break;
}
}
After adding above code, the final code in MainActivity.java
:
package com.myproject
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
class MainActivity : ReactActivity() {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "MyProject"
/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
/**
* Handling Permissions in Native Code: handling the CustomModule results of permission requests
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 100: // CAMERA_PERMISSION_CODE
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
} else {
// Permission denied
}
break;
case 101: // RECORD_AUDIO_PERMISSION_CODE
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
} else {
// Permission denied
}
break;
}
}
}
D. Add Permissions to AndroidManifest.xml
Make sure to add the required permissions to your AndroidManifest.xml
file:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET"/>
Conclusion
By following these steps, you can create a custom React Native plugin to call native Java code for handling camera and recording permissions. This approach allows you to harness the capabilities of the native platform while using React Native for cross-platform development.
Use Auto-Linking (React Native 0.60 and Above)
1. Install Dependencies:
npm install [package-name]
Or just use npm install
to install all dependencies in package.json file.
2. Run React Native:
npx react-native run-android
npx react-native run-ios
For iOS: Navigate to the ios
directory and run pod install
to install the necessary CocoaPods dependencies:
cd ios
pod install
cd ..
Known error while running Android build: npx react-native run-android
SDK location not found. Define a valid SDK location with an ANDROID_HOME environment variable or by setting the sdk.dir path in your project’s local properties file at ‘/Users/ankitmaheshwari/Data/React-Projects/POC/MyProject/android/local.properties’.
To know Android_Home path:
To fix this, update local.properties
File:
If environment variables are less familiar, you can specify the SDK location directly in your project:
- Navigate to the
android/local.properties
file in your project directory. - If it doesn’t exist, create a new file named
local.properties
. - Add the line
sdk.dir=/path/to/android/sdk
(replace/path/to/android/sdk
with the actual path). - Save the
local.properties
file.
Restart Terminal:
After making changes to environment variables, restart your terminal window for the changes to take effect.
Verify Installation:
Once you’ve set ANDROID_HOME
or updated local.properties
, try building your React Native app again.