jamesmontemagno / Xamarin.Plugins

Cross-platform Native API Access from Shared Code!
MIT License
1.3k stars 380 forks source link

Media on Android: Assembly-wide UsesPermission prevents compatibility with Nexus 7 #189

Closed cleardemon closed 8 years ago

cleardemon commented 8 years ago

I doubt this can be fixed without a change to Xamarin.Android, but I'm putting this out there in case anyone else has the same problem.

Adding the Media plugin to the Android project will automatically declare that the CAMERA permission is required by the app:

[assembly: UsesPermission(Android.Manifest.Permission.Camera)]

This single settings prevents Google Play from listing the Nexus 7 as compatible, because that device does not have a camera on the back (as explained here). Note that the app will still work when running via the debugger or installing manually -- it's just the Google Play Store saying it isn't compatible and preventing install.

Google Play Store

Why don't I think it can be fixed right now? Because the UsesPermission attribute does not seem to support the required attribute in the Android manifest.

I believe the workaround seems to be to manually set the permission in AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" android:required="false" />

I am currently waiting for the store to update with my new build, will post again saying if this fixed it.

jamesmontemagno commented 8 years ago

Let me know, and I can fix the attribute. This was a change that I made to my plugins to simplify the development. Odd ass the Nexus 7 actually does have a camera, so that would seem odd to me.

jamesmontemagno commented 8 years ago

So, what you actually want is:

<uses-feature android:name="android.hardware.camera" android:required="false" />
and probably:
 <uses-feature android:name=“android.hardware.camera.autofocus" android:required="false" />

The permission is a permission, but the feature is auto detected by google play.

jamesmontemagno commented 8 years ago

Take a look here: http://developer.android.com/guide/topics/manifest/uses-feature-element.html#permissions-features

jamesmontemagno commented 8 years ago

I have added this to the documentation: https://github.com/jamesmontemagno/Xamarin.Plugins/blob/master/Media/README.md#important

Thanks for the feedback :)

cleardemon commented 8 years ago

Cheers James, been a busy day, but still waiting for Google Play to update. I see uses-features has the attribute rather than uses-permission, I guess a bit of misinformation when I was Googling the problem, but your solution seems to be the way to go.

Once it updates, I'll update it again with your proposed change.

cleardemon commented 8 years ago

According to that page above, you can use android.hardware.camera.any to specify that any camera is used (front or back). Explicitly stating android.hardware.camera refers only to the back camera, which the Nexus 7 doesn't have.

But, this doesn't appear to fix the problem. I have set the following in AssemblyInfo.cs:

[assembly: Android.App.UsesFeature("android.hardware.camera.any", Required=false)]
[assembly: Android.App.UsesFeature("android.hardware.camera.autofocus", Required=false)]

The manifest is generated (in obj/Release/android/AndroidManifest.xml) as the following:

screen shot 2016-01-20 at 10 42 07

But, Google Play Store still lists it as incompatible. There aren't any other features that would prevent the Nexus 7 from being incompatible, and it does run fine when I run it on the actual device via Xamarin Studio.

At a loss with this one!

jamesmontemagno commented 8 years ago

can you try it with also:

[assembly: Android.App.UsesFeature("android.hardware.camera", Required=false)]

according to: http://stackoverflow.com/questions/12010383/nexus-7-support-for-android-application-manifest-assembly

cleardemon commented 8 years ago

Yup! Listing all three seems to ensure Nexus 7 compatibility. I guess Google's notion of inheritance doesn't apply to the Store logic :)

screen shot 2016-01-21 at 10 52 29

Problem solved. Thanks again, James!

wouterh commented 8 years ago

Does the plugin actually need the CAMERA permission? Since you're launching the camera app to take the picture, it's that one that needs the CAMERA permission. I also developed on a native android app that doesn't have the CAMERA permission set, but can take pictures just fine by launching the camera app through an intent.

jamesmontemagno commented 8 years ago

@wouterh yes for the uses-feature... I will investiage the actual permission usage... would be interested if it did not http://developer.android.com/training/camera/photobasics.html

wouterh commented 8 years ago

@jamesmontemagno I am pretty sure the uses-feature is enough. As I already mentioned, I have a native app that doesn't declare the CAMERA permission, but can take pictures through an intent to the camera app just fine.

wouterh commented 8 years ago

BTW, if we are talking permissions. The MediaPickerActivity should process/copy the picked file before calling finish(), which it currently does not. I had to patch this for an app to be able to pick photos from the Google Photos app. It's still on my TODO list to prepare a pull request for that, but I didn't get to it yet.

The reason is that the Google Photos app (and probably others like the Google Drive app etc) grant a temporary URI permission for the picked file (http://developer.android.com/guide/topics/security/permissions.html#uri). That temporary permission only lasts until the activity that called startActivityForResult() finishes.

jamesmontemagno commented 8 years ago

@wouterh I am going to remove the permission in the next release on NuGet.

As for the URI permission I made this change here: https://github.com/jamesmontemagno/Xamarin.Plugins/blob/master/Media/Media/Media.Plugin.Android/MediaPickerActivity.cs#L313-L315

I do believe it only effects newer OS releases, but can't confirm.

jamesmontemagno commented 8 years ago

Fixed in 2.2.x

wouterh commented 8 years ago

@jamesmontemagno for the URI permission to work on my test devices, I had to change these lines: https://github.com/jamesmontemagno/Xamarin.Plugins/blob/master/Media/Media/Media.Plugin.Android/MediaPickerActivity.cs#L328-L330

to

future.ContinueWith(t => OnMediaPicked(t.Result)).ContinueWith(t => Finish());
jamesmontemagno commented 8 years ago

Gotcha. Seem like if you just removed my version check it would be the same thing though.