react-native-audio-recorder-player
react-native-audio-recorder-player copied to clipboard
Recording not possible in Android 13
In Android 13 (Api Level 33) WRITE_EXTERNAL_STORAGE is not granted and the permission check will fail. The library defines these permissions in the AndroidManifest.xml and in RNAudioRecorderPlayerModule.kt startRecorder explicitly checks and asks for the permissions RECORD_AUDIO and WRITE_EXTERNAL_STORAGE. As the Storage-permission can not be granted it will fail. The library does not record with the exception "Try again after adding permission.".
If the permission check is removed it will need to be asked separately by PermissionsAndroid if writing to external storage (not in app sandbox) is needed.
If this is the case, you can use this patch-package fix:
react-native-audio-recorder-player+3.5.1.patch
diff --git a/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt b/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt
index 8bd601e..16b46da 100644
--- a/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt
+++ b/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt
@@ -38,11 +38,9 @@ class RNAudioRecorderPlayerModule(private val reactContext: ReactApplicationCont
fun startRecorder(path: String, audioSet: ReadableMap?, meteringEnabled: Boolean, promise: Promise) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
- (ActivityCompat.checkSelfPermission(reactContext, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED ||
- ActivityCompat.checkSelfPermission(reactContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
+ (ActivityCompat.checkSelfPermission(reactContext, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions((currentActivity)!!, arrayOf(
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.WRITE_EXTERNAL_STORAGE), 0)
+ Manifest.permission.RECORD_AUDIO), 0)
promise.reject("No permission granted.", "Try again after adding permission.")
return
}
Hey, thanks for making this, it helped me out.
I had to add \ No newline at end of file
at the end of the file make it work.
Not sure if this note is actually relevant to this Android 13 update or if it was alway like this, but sharing none the less - I needed to set unique file names, so I had to define the path. The path that works is data/user/0/com.[your-app-name]/cache/${fileName}.mp4
For reference, here's the full function:
onStartRecord = async () => {
const fileName = `record-${new Date().getTime()}`;
const path = Platform.select({
ios: `${fileName}.m4a`,
android: `data/user/0/com.flow_app/cache/${fileName}.mp4`,
});
const result = await audioRecorderPlayer.startRecorder(path);
audioRecorderPlayer.addRecordBackListener((e) => {
return;
});
};
@thinkmobilede Is this change compatible with API levels < 33? In other words - will this change break the app on older versions of Android?
@thinkmobilede Is this change compatible with API levels < 33? In other words - will this change break the app on older versions of Android?
As mentioned in the issue if you want to write the file to external storage (not app sandbox) you will need ask for the write permissions with PermissionsAndroid. You could also adapt the change above to still ask for the permissions by the library depending on the API level but then still you need to handle writing the file correctly on Android 11+ as the legacy storage system stops working there.
I feel like react-native-audio-recorder-player
is doing too much. The startRecording
method should just try to record, and then, if the method fails it could warn the user about the possibility that permissions are not granted.
I feel like
react-native-audio-recorder-player
is doing too much. ThestartRecording
method should just try to record, and then, if the method fails it could warn the user about the possibility that permissions are not granted.
Many RN libraries want to simplify the usage this way, you can still handle the permissions yourself before using the library (e. g. in your user flow). The simplification here fails because the permission is not granted and the library not maintained for some time. You can also fork the library and remove the permissions handling for your usage.
I feel like
react-native-audio-recorder-player
is doing too much. ThestartRecording
method should just try to record, and then, if the method fails it could warn the user about the possibility that permissions are not granted.Many RN libraries want to simplify the usage this way, you can still handle the permissions yourself before using the library (e. g. in your user flow). The simplification here fails because the permission is not granted and the library not maintained for some time. You can also fork the library and remove the permissions handling for your usage.
Hello, I am back here. Sorry that I was very busy. I am trying to follow up on issues today. Do you think the permission check should be removed from the module?
IMO it should be at least moved to a separate fn like "requestPermissions".
is there any news on this issue? Since this library cannot be used on android 13 as of now :/
patch for 3.5.3 😢
diff --git a/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt b/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt
index 5cb9bbf..f2fb693 100644
--- a/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt
+++ b/node_modules/react-native-audio-recorder-player/android/src/main/java/com/dooboolab.audiorecorderplayer/RNAudioRecorderPlayerModule.kt
@@ -41,10 +41,8 @@ class RNAudioRecorderPlayerModule(private val reactContext: ReactApplicationCont
// TIRAMISU (33)
// https://github.com/hyochan/react-native-audio-recorder-player/issues/503
if (Build.VERSION.SDK_INT < 33 &&
- (ActivityCompat.checkSelfPermission(reactContext, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED ||
- ActivityCompat.checkSelfPermission(reactContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
+ (ActivityCompat.checkSelfPermission(reactContext, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions((currentActivity)!!, arrayOf(
- Manifest.permission.RECORD_AUDIO,
Manifest.permission.WRITE_EXTERNAL_STORAGE), 0)
promise.reject("No permission granted.", "Try again after adding permission.")
return
I was able to fix this issue for 3.5.3 without patching node_modules
. I used the react-native-permissions library to ask for the missing WRITE_EXTERNAL_STORAGE
permission.
Here's some sample code for Android:
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
const micStatus = await request(PERMISSIONS.ANDROID.RECORD_AUDIO);
const mediaStatus = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
export const requestAllPermissions = async () => {
const micStatus = await request(PERMISSIONS.ANDROID.RECORD_AUDIO);
const mediaStatus = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
return micStatus === RESULTS.GRANTED && mediaStatus === RESULTS.GRANTED;
};
After asking the user for these permissions, I was able to both record and replay audios.
Note: It goes without saying that these permissions must also be included in android/app/src/main/AndroidManifest.xml
.
I was able to fix this issue for 3.5.3 without patching
node_modules
. I used the react-native-permissions library to ask for the missingWRITE_EXTERNAL_STORAGE
permission.
I doubt that you tested this on an Android 13 device. This issue is about running on an Android 13 device and this Android version does not grant WRITE_EXTERNAL_STORAGE anymore, so you will not be able to get it and it will fail.
I doubt that you tested this on an Android 13 device. This issue is about running on an Android 13 device and this Android version does not grant WRITE_EXTERNAL_STORAGE anymore, so you will not be able to get it and it will fail.
@thinkmobilede Unfortunately, you're right. Although I did test on Android 13, it turns out I was running API level 32 - which worked fine. Once I tested on API level 33, it did not work, just as you said.
hello any update on this one? i have the same issue.
Hello, did someone solve the problem? I have the same problem.
I solved it by removing the permission check via patch-package
and did my own requesting using react-native-permissions
I solved it by removing the permission check via
patch-package
and did my own requesting using react-native-permissions
It worked for me too, I also added these lines.
Android
NOTE: The problem is fixed in version 0.70.7.
/node_modules/react-native/Libraries/PermissionsAndroid/NativePermissionsAndroid.js
...
| 'android.permission.RECEIVE_WAP_PUSH'
| 'android.permission.RECEIVE_MMS'
| 'android.permission.WRITE_EXTERNAL_STORAGE'; <- removed this and
| 'android.permission.WRITE_EXTERNAL_STORAGE' <- added these 3
| 'android.permission.POST_NOTIFICATIONS'
| 'android.permission.READ_MEDIA_AUDIO';
...
/node_modules/react-native/Libraries/PermissionsAndroid/PermissionsAndroid.js
...
RECEIVE_MMS: 'android.permission.RECEIVE_MMS',
READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE',
WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE',
POST_NOTIFICATIONS: 'android.permission.POST_NOTIFICATIONS', <- added this
READ_MEDIA_AUDIO: 'android.permission.READ_MEDIA_AUDIO', <- added this
...
WRITE_CALL_LOG: string,
WRITE_CONTACTS: string,
WRITE_EXTERNAL_STORAGE: string,
POST_NOTIFICATIONS: string, <- added this
READ_MEDIA_AUDIO: string, <- added this
....
Earlier my Android.Manifest is like this one
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="+++++++++++"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <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"> <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
After the change it was like
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="++++++++++++"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS'" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <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"> <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
Now its working properly and then along with that i changed the version from 3.5.1 to 3.5.3 of this package react-native-audio-recorder-player
``
Please, I need help! It keeps warning that 'try again after adding permissions'
Android API 34
react-native: "0.71.8" react-native-audio-recorder-player: "^3.3.4"
const requestPermissions = async () => { const atLeastAndroid13 = Platform.OS === 'android' && Platform.Version >= 33;
if (Platform.OS === 'android') {
try {
const grants = await PermissionsAndroid.requestMultiple(
atLeastAndroid13
? [PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO]
: [
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
],
);
console.log({grants});
if (
atLeastAndroid13
? grants['android.permission.RECORD_AUDIO'] === PermissionsAndroid.RESULTS.GRANTED &&
grants['android.permission.READ_MEDIA_AUDIO'] === PermissionsAndroid.RESULTS.GRANTED
: grants['android.permission.WRITE_EXTERNAL_STORAGE'] === PermissionsAndroid.RESULTS.GRANTED &&
grants['android.permission.READ_EXTERNAL_STORAGE'] === PermissionsAndroid.RESULTS.GRANTED &&
grants['android.permission.RECORD_AUDIO'] === PermissionsAndroid.RESULTS.GRANTED
) {
console.log('permissions granted');
} else {
console.warn('All required permissions not granted');
return false;
}
} catch (err) {
console.warn(err);
return false;
}
}
return true;
}
const permissionsGranted = await requestPermissions();
if (!permissionsGranted) {
Alert.alert('Permissions not granted', 'Please grant the necessary permissions in settings.');
return;
}
if (status === 'start') {
// let audioRecorderPlayer = new AudioRecorderPlayer();
try {
const uri = await audioRecorderPlayer.startRecorder(path);
console.log('uri:', uri);
NotificationService.create(order.userId, 'recording-started', I18n.locale === 'he' ? 'heb' : I18n.locale === 'en' ? 'en' : 'es');
setRecordUri(uri);
audioRecorderPlayer.addRecordBackListener((e) => {
const timer = convertMilisecToTimer(e.currentPosition);
setRecordTime(timer);
console.log({timer});
return
});
console.log("#########################TIEMPO#######################")
BackgroundTimer.stopBackgroundTimer();
setStatus('progress');
} catch (err) {
console.log("el error en el try...")
console.error(err);
}
} else if (status === 'pause') {
try {
await audioRecorderPlayer.resumeRecorder();
BackgroundTimer.stopBackgroundTimer();
setStatus('progress');
} catch (err) {
console.log(`Pause ::> status: ${status}, Record timer: ${recordTime}`)
console.warn(err);
}
} else if (status === 'progress') {
try {
await audioRecorderPlayer.pauseRecorder();
setStatus('pause');
// setTimeLeft(timeHold);
} catch (err) {
console.log(`Progress ::> status: ${status}, Record timer: ${recordTime}, recorder: ${JSON.stringify(audioRecorderPlayer)}`)
console.warn(`Este es el null : ${err}`);
}
}
@ecastago What's the actual version of react-native-audio-recorder-player? Many months ago I got this message sometimes and had to apply the patch, but after upgrading to a more recent version, the patch isn't needed anymore ( pretty sure about that, feel free to correct me if I'm wrong ) and I stopped getting these errors. I'm using version 3.6.7.
in case it helps, i'm using RN 0.73.6