pwlin / cordova-plugin-file-opener2

A File Opener Plugin for Cordova
MIT License
313 stars 586 forks source link

Error while Opening the File #130

Closed jinuem closed 7 years ago

jinuem commented 7 years ago

I tried this in Android 6.0. Used this Plugin Using Ionic Native

code :

location = "/storage/emulated/0/Android/data/com.jinuxlabs.moviesapp/files/Resume.pdf";
        fileOpener.open(location, 'application/pdf')
            .then(function () { return console.log('File is opened'); })
            .catch(function (e) { return console.log('Error openening file', e); });

If i give wrong file name, it shows No files in that name correctly. But if Files are there! But it throws Following Error.

Error openening file Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

Versions: Ionic - 2.2.3 Cordova: 6.5.0 Android 6.1.2

Any Idea? why this Error Throws up.

pwlin commented 7 years ago

Are you using FileOpener2 version 2.0.16 or higher?

Do you have opener_paths.xml file in res/xml folder?

jinuem commented 7 years ago

@pwlin Using 2.0.16 and also i have opener_paths.xml in res/xml folder ..

Here is the code in the File

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="files" path="." />
    <external-files-path name="external_files" path="." />
    <external-path name="external_files" path="." />
    <cache-path name="cached_files" path="." />
    <external-cache-path name="cached_files" path="." />
</paths>
pwlin commented 7 years ago

I am really not sure how Ionic Native works. Can you try it with normal Ionic to see if that works?

jinuem commented 7 years ago

@pwlin No, its not different. Both are same. Just declarations with Angular 2+ are different.

location = "/storage/emulated/0/Android/data/com.jinuxlabs.moviesapp/files/Resume.pdf";
        fileOpener.open(location, 'application/pdf')
            .then(function () { return console.log('File is opened'); })
            .catch(function (e) { return console.log('Error openening file', e); });

but this Code is pure js. it should work right??

More Info: https://ionicframework.com/docs/native/file-opener/

pwlin commented 7 years ago

Yes I have noticed from long time ago that they have listed this plugin in their sidebar, but that does not mean that this plugin is affiliated with Ionic. I think they just list a couple of popular plugins.

But who knows, maybe they do offer support for the listed plugins. Have you tried to ask for help in Ionic forums?

pwlin commented 7 years ago

One more thing: I think hard-coding file paths like /storage/emulated/0/Android/data/com.xxx.xxx/..... does not work with newer Android versions anymore. You should create a File handler object and then use toURL() function. Be sure to read cordova-plugin-file docs

jinuem commented 7 years ago

Ok. Thank you. Will look into New Docs..

pwlin commented 7 years ago

Let us know if you've find a solution to this problem, it might help other people too. Also, post to Ionic forums and ask if someone can help you.

jcdickman commented 7 years ago

You ever find a solution to this? On Android 6.0.1 (Samsung) when using "ionic run android" I am still getting:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

I did set a breakpoint in the plugin java, line 109 in FileOpener2.java. What I found was that, when using "ionic run android" or "cordova run android" to launch the app on the device, the result of cordova.getActivity().getPackageName() is coming back as com.package.PackageName.release, which constructs an authority string like com.package.PackageName.release.opener.provider, which does not match the one in the AndroidManifest added by the plugin which is com.package.PackageName.opener.provider. As a result, in the FileProvider class, the ProviderInfo info object is null leading to the attempt to invoke a virtual method on a null object reference.

I have confirmed this is the issue by manually changing the authority string to one that matches the AndroidManifest authority, which allows the file to be opened successfully. However, that is obviously a hack, any ideas why this is occurring or how we might solve the issue?

--- edited to say "cordova.getActivity().getPackageName()" ---

jcdickman commented 7 years ago

So I altered the plugin.xml so that it would output the following provider element in the AndroidManifest, and it seems to fix the problem:

`

    </provider>`

Do you think that is a viable solution for the plugin as a whole? Or is this just something that solves my problem but might cause issues for others?

pwlin commented 7 years ago

@jcdickman so you basically modified the value of android:authorities from $PACKAGE_NAME.opener.provider to ${applicationId}.opener.provider, and that fixed the problem, right?

jcdickman commented 7 years ago

Yes, that's it. I am honestly not sure why that was happening (the appending of .release), guessing it's happening in some ionic or cordova gradle file, but using that wildcard fixed the authority issue.

pwlin commented 7 years ago

Did you add ${applicationId}.opener.provider directly to your own app's AndroidManifest.xml? Or did you modify this plugin's plugin.xml and rebuilt your own app?

jcdickman commented 7 years ago

Yeah, I just forked the repo and pushed the change there: https://github.com/jcdickman/cordova-plugin-file-opener2

pwlin commented 7 years ago

I am worried that this is an Ionic-specific issue and won't be compatible with normal Cordova way of doing things. Because $PACKAGE_NAME will return this plugin's Id, while ${applicationId} will return main app's Id.

Can you please do a last test for me:

Can you change android:authorities value to io.github.pwlin.cordova.plugins.fileopener2.opener.provider , rebuild your app and see if that works? Maybe we should hard code it like that. Really appreciate your testing.

jcdickman commented 7 years ago

From my testing, $PACKAGE_NAME returns the package name of the main application, not the plugin's ID. The result of using $PACKAGE_NAME is the main app's package name gets hard coded into the android:authorities in the main app's AndroidManifest.

Now, what cordova.getActivity().getPackageName() is actually returning is not the package name, it's the applicationId at runtime (getPackageName() is a misnomer). This is based on the package name, and is often the same as the package name, but can be different for different build variants (debug, test, release, etc). This is apparently common practice (see here https://developer.android.com/studio/build/application-id.html).

So, my solution allows your plugin to do a valid authority check even when the main app is being run with a build variant applicationId that is slightly different than the original package name.

I did test it the way you asked though, and I got the exact same error, because it was trying to compare the main app's applicationId+opener.provider (com.package.packageName.release.opener.provider) to the hard coded io.github.pwlin.cordova.plugins.fileopener2.opener.provider.

jcdickman commented 7 years ago

And of course you're welcome, and thank you for developing this very useful plugin!

jcdickman commented 7 years ago

I tracked down the "Cordova way" of creating build variants as well, which is exactly what was going on in my project: https://cordova.apache.org/docs/en/latest/guide/platforms/android/

ext.postBuildExtras = { android.buildTypes.debug.applicationIdSuffix = '.debug' }

in my case it was applying .release suffix for release builds.

pwlin commented 7 years ago

I have merged your changes and pushed a new version (2.0.18) to npm. Can you please test to see if it works now? Thank you for your help.

jcdickman commented 7 years ago

Sure thing, in the middle of a deployment right now but I'll give it a whirl in a bit.

On Thu, Jun 1, 2017 at 3:48 PM, pwlin notifications@github.com wrote:

I have merged your changes and pushed a new version (2.0.18) to npm. Can you please test to see if it works now? Thank you for your help.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/pwlin/cordova-plugin-file-opener2/issues/130#issuecomment-305615835, or mute the thread https://github.com/notifications/unsubscribe-auth/ACoCu3TZX7X52Z1K7mKfX5nZcXUAR8WCks5r_yOSgaJpZM4NqEyS .

pwlin commented 7 years ago

No hurry, your own job is more important!

jcdickman commented 7 years ago

Just tested it with your new version, all is well.

pwlin commented 7 years ago

great! thanks for your help!

jinuem commented 7 years ago

Cool :)