triniwiz / nativescript-videorecorder

:video_camera: NativeScript plugin for Video Recording . :video_camera:
Apache License 2.0
43 stars 29 forks source link

VideoRecorder: crash on Android #41

Closed Tronix117 closed 6 years ago

Tronix117 commented 6 years ago

If the demo apps cannot help and there is no issue for your problem, tell us about it

Can not start the videorecorder on Android, working fine on iOS.

Which platform(s) does your issue occur on?

Please, provide the following version numbers that your issue occurs with:

Is there any code involved?

Here is the call to the videorecorder:

videorecorder.record({
  saveToGallery: false,
  duration: 240,
  format: 'mp4',
  size: 20,
  hd: true,
  explanation: 'l\'accès à la caméra est nécessaire'
})

I have this in AndroidManifest.xml:

        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />   

Here is the error:

JS: 'java.lang.NullPointerException: Attempt to invoke virtual method \'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)\' on a null object reference
JS:     android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:591)
JS:     android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:565)
JS:     android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:403)
JS:     com.tns.Runtime.callJSMethodNative(Native Method)
JS:     com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1088)
JS:     com.tns.Runtime.callJSMethodImpl(Runtime.java:970)
JS:     com.tns.Runtime.callJSMethod(Runtime.java:957)
JS:     com.tns.Runtime.callJSMethod(Runtime.java:941)
JS:     com.tns.Runtime.callJSMethod(Runtime.java:933)
JS:     com.tns.gen.org.nativescript.widgets.Async_CompleteCallback.onComplete(Async_CompleteCallback.java:12)
JS:     org.nativescript.widgets.Async$Http$HttpRequestTask.onPostExecute(Async.java:585)
JS:     org.nativescript.widgets.Async$Http$1$1.run(Async.java:486)
JS:     android.os.Handler.handleCallback(Handler.java:751)
JS:     android.os.Handler.dispatchMessage(Handler.java:95)
JS:     android.os.Looper.loop(Looper.java:154)
JS:     android.app.ActivityThread.main(ActivityThread.java:6119)
JS:     java.lang.reflect.Method.invoke(Native Method)
JS:     com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
JS:     com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)'
JS: '=== dump(): dumping members ===
Tronix117 commented 6 years ago

I add success using "nativescript-videorecorder@2.0.4" and manualy requesting permissions like so:

     if (isAndroid) {
      await requestPermissions([
        (<any>android).Manifest.permission.WRITE_EXTERNAL_STORAGE,
        (<any>android).Manifest.permission.RECORD_AUDIO,
        (<any>android).Manifest.permission.CAMERA
      ])
    }
Tronix117 commented 6 years ago

Ok So update on this issue:

Android Manifest should have (in the <application>):

        <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="fr.wikodit.prosapiens.provider"
                android:exported="false"
                android:grantUriPermissions="true">
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
        </provider>

Then in the file App_Resources/xml/provider_paths.xml you should have (it does not seem to pick the one in the module, I had to manualy create it):

<?xml version="1.0" encoding="utf-8"?>
<paths
    xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="videos" path="." />
    <cache-path name="temps_videos" path="."/>
</paths>

Then the module code needs to be modified a bit like so:

if (!options.saveToGallery) {
                    if (sdkVersionInt >= 21) {
                        path = app.android.currentContext.getExternalFilesDir(null);
                        file = new java.io.File(path, fileName);
                        tempPictureUri = android.support.v4
                            .content.FileProvider.getUriForFile(app.android.foregroundActivity, pkgName + '.provider', file);
                    }
                    else {
                        path = fs.path.join(fs.knownFolders.temp().path, fileName);
                        file = new java.io.File(path);
                        tempPictureUri = android.net.Uri.fromFile(file);
                    }
                    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, tempPictureUri);
                }

Also path = app.android.currentContext.getExternalFilesDir(null); may be conditionaly determined using a configuration variable, depending on cases, we may not want to store it in a temporary location. Or maybe we keep it simple, and if the developer want to move it in another location, it can do it like he have the path ?

I used getExternalFilesDir instead of a temp directory, because it was easier for me to test, it should work with the temp directory