anotherlab / UsbSerialForAndroid

A Xamarin C# port of the Java usb-serial-for-android library
MIT License
160 stars 70 forks source link

Requesting Permission has been failed on Android 14 #56

Open endless-runner-007 opened 10 months ago

endless-runner-007 commented 10 months ago

On Android 14, There are 2 problems

  1. Receiver_Export issue

image

this error occurs on the following code line, UsbSerialForAndroid/Extensions/UsbManagerExtensions.cs context.RegisterReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION));

I changed it to following

if (Build.VERSION.SdkInt >= BuildVersionCodes.Tiramisu) context.RegisterReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION), (ActivityFlags)ReceiverFlags.Exported); else context.RegisterReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION));

  1. PendingIntent parma issue

image

this error occurs on the following code line PendingIntentFlags pendingIntentFlags = Build.VERSION.SdkInt >= BuildVersionCodes.S ? PendingIntentFlags.Mutable : 0;

I changed it Immutable. But I can't get the permission.

S-CODE-pl commented 9 months ago

I have the same issue, anyone find solution?

endless-runner-007 commented 9 months ago

I found the solution https://stackoverflow.com/questions/77688241/requesting-usb-permission-has-been-failed-on-android-14-xamarin/77691737#77691737

memsom commented 4 months ago

I have the code fixed here: https://github.com/memsom/UsbSerialForAndroid I would submit a pull request, but I also removed the legacy .Net runtimes, so it might not be exactly what you want. The changes needed are here: https://github.com/memsom/UsbSerialForAndroid/blob/a00c01134c125c00b1e24a3aa23f7cb5252ef8f3/UsbSerialForAndroid/Extensions/UsbManagerExtensions.cs#L43

memsom commented 4 months ago

You actually also need to export the Receiver too -

https://github.com/memsom/UsbSerialForAndroid/blob/6bb07e570506d3487e6f754ee869464def961874/UsbSerialForAndroid/Extensions/UsbManagerExtensions.cs#L33

So the full fix would be:

 public static Task<bool> RequestPermissionAsync(this UsbManager manager, UsbDevice device, Context context)
        {
            var completionSource = new TaskCompletionSource<bool>();

            var usbPermissionReceiver = new UsbPermissionReceiver(completionSource);

            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
#pragma warning disable CA1416
                //this is checking that it is API 26 or greater, bu the compiler doesn't see it that way. So we have to add in a pragma
                context.RegisterReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION), ReceiverFlags.Exported);
#pragma warning restore CA1416
            }
            else
            {
                context.RegisterReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION));
            }

            // Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
#if NET6_0_OR_GREATER
            PendingIntentFlags pendingIntentFlags = Build.VERSION.SdkInt >= BuildVersionCodes.S ? PendingIntentFlags.Mutable : 0;
#else
            PendingIntentFlags pendingIntentFlags = Build.VERSION.SdkInt >= (BuildVersionCodes)31 ? (PendingIntentFlags).33554432 : 0;
#endif
            var intent = new Intent(ACTION_USB_PERMISSION);
            // we need this for Android 34+ as apparently, security. If you follow Google's docs,
            // you will spend a lot of time fighting with the API not actually replying with any
            // useful data... because Immutable Intents *can;t* be changed, so the API is basically
            // hobbled.
            if (Build.VERSION.SdkInt >= BuildVersionCodes.UpsideDownCake)
            {
                intent.SetPackage(context.PackageName);
            }

            var pendingIntent = PendingIntent.GetBroadcast(context, 0, intent, pendingIntentFlags);

            manager.RequestPermission(device, pendingIntent);

            return completionSource.Task;
        }

If you do not do those two things in Android 14, it basically just doesn't work.

Edit: I used ReceiverFlags.Exported, but you might be able to use the ReceiverFlags.NotExported, I'm not an Android API expert and so I don;t know what the difference is and haven't experimented outside of this type of "fix" in previously working code.

This is my own personal opinion, but the stuff they have changed recently seems to have made everything less easy to do simple things and have made everything more locked down in a "not good" type of way from a developers point of view. (External file system access, I see you there in the corner... grrr.)

memsom commented 4 months ago

Okay - I tried it in the test app, and not exporting the BroadcastReceiver doesn't seem to make any difference there.

Apparently, it should be automatically exported if you have an intent list, but then to be honest the attributes in Xamarin projects are very vague as to what they generate in the actual AndroidManifest.xml, so I have started to avoid them. They do not seem to add in the extra stuff Android 14 seems to require.

There was another weird bug in the Hex dumping code. Every now and again it was throwing with an index out of bounds. I fixed it by hiding the exception, but I see a # in dumped hex every now and again, and that is the char I replaced the thrown exception with. So it is for sure happening regularly for me under .Net8.

anotherlab commented 4 months ago

@memsom Each release by Google is another rachet of the security screw. Which makes projects like this a moving target.

I'm sorry, but we are only looking at code changes that have been submitted as pull requests.

memsom commented 4 months ago

@anotherlab Okay, I can do you a PR. My main issue is that you are using really old runtimes and I simply don't have them installed anymore. If I submit a PR that removes the stuff that is out of support also, would that be acceptable? Or would you want 2 separate PRs?

anotherlab commented 4 months ago

@memsom By old runtimes, do you mean Xamarin Android (as opposed to Microsoft Android)?

memsom commented 4 months ago

@memsom By old runtimes, do you mean Xamarin Android (as opposed to Microsoft Android)?

I can have a look and see, but probably. We now have a fork of the code working on Android 14 with both FTDI and CDC drivers, so with these changes it should be possible to continue using the code for the foreseeable future as-is. The fixes I posted are what was needed to fix it for Android 14. I will get you a PR, but it isn't a super high priority at the moment. It would probably be quicker for you to do the fix yourself - if you want to support MAUI, this is needed with DotNet 8.0, which targets API level 34.

Edit: I don't mean to sound like I don;t care, I do. I just don't have the free time at the moment. Porting Xamarin Forms to MAUI is not as straight forward as Microsoft claims so I'm very busy in my day job currently, and I would need to do the PR on my own time, despite me not actually needing this for any personal projects..

Xamarin Android is now legacy and is out of support, and so continuing to support it from here has diminishing returns.

memsom commented 3 months ago

Forgive me, but I looked and I don't see any commits against this issue. Is this really complete? Closing this issue seems extremely premature if not. Closing the issue will not magically make Android 14 work. The fix is a dozen lines of changes. But this library is useless without those fixes.

anotherlab commented 3 months ago

@memsom This issue should not have been closed and I re-opened it.

I am looking at your suggested changes and will create a PR, hopefully this weekend (this is not my day job).

memsom commented 3 months ago

I am looking at your suggested changes and will create a PR, hopefully this weekend (this is not my day job).

If it helps I can probably package up our current changes and put them in my copy of the repo. (I don't remember if we changed anything else or not since I forked the code.) It should then just be a case of you working out what needs to be added to make it compile for the older platforms you support. A good compare tool should make light work of it.

I'm sorry I haven't been able to help more. We'd really like to see a nuget that supports the Microsoft Android target compatible with Maui, so I might circle back on that later if you have no time. At the moment we have the code in our Maui repository, but I'd rather it was an external dependency.

andrea-993 commented 1 week ago

Thanks for your fix memsom i made it work but add to apply a small change to your code: PendingIntentFlags pendingIntentFlags = Build.VERSION.SdkInt >= (BuildVersionCodes)31 ? (PendingIntentFlags).33554432 : 0; into this: PendingIntentFlags pendingIntentFlags = Build.VERSION.SdkInt >= (BuildVersionCodes)31 ? (PendingIntentFlags)33554432 : 0;

I removed the dot otherwise it would get interpreted as double and then converted to int and becomes 0 instead of 33554432 did you get a different result?