Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow adding foreground service types dynamically #1050

Merged
merged 6 commits into from
Sep 11, 2024
Merged

feat: allow adding foreground service types dynamically #1050

merged 6 commits into from
Sep 11, 2024

Conversation

santhoshvai
Copy link
Contributor

@santhoshvai santhoshvai commented Jun 17, 2024

Allow adding foreground service types dynamically for Android 14 compatibility

Why ?

From Android 14 (API level 34) or higher, the operating system checks when you create a foreground service to make sure your app has all the appropriate permissions for that service type. For example, when you create a foreground service of type microphone, the operating system verifies that your app currently has the RECORD_AUDIO permission. If you don't have that permission, the system throws a SecurityException.

How does this PR solve it?

To support this, a notification can now be created with foregroundServiceTypes property which specifies the types to be used while creating the service:

import notifee, { AndroidForegroundServiceType } from '@notifee/react-native';

notifee.displayNotification({
  title: 'Foreground service',
  body: 'This notification will exist for the lifetime of the service runner',
  android: {
    channelId,
    asForegroundService: true,
    foregroundServiceTypes: [AndroidForegroundServiceType.FOREGROUND_SERVICE_TYPE_CAMERA, AndroidForegroundServiceType.FOREGROUND_SERVICE_TYPE_MICROPHONE],
  },
});

If on runtime a new permission is granted from the user, the notification can be posted again (same notification id and channel id) with the new foregroundServiceTypes.

Fixes

@CLAassistant
Copy link

CLAassistant commented Jun 17, 2024

CLA assistant check
All committers have signed the CLA.

@josegiufrida
Copy link

I think that Notifee's AndroidManifest should not include:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

Since the foreground service could have other types and the resulting AndroidManifest would still have this permission

@santhoshvai
Copy link
Contributor Author

@josegiufrida

the tools:replace="android:foregroundServiceType" will allow to override the types. So having data sync is a sensible default when there is no default overrride.

@josegiufrida
Copy link

Yes tools:replace="android:foregroundServiceType" will replace the types, and it's working fine.

But look at the following case. Only Location type is needed, so user add to his AndroidManifest:

Permission request:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

And types replace:
<service android:name="app.notifee.core.ForegroundService" android:foregroundServiceType="location" />

The problem here is that the resulting AndroidManifest will have both permission requirements:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

Which causes problems when uploading to the Play Store, since proof of the use of "FOREGROUND_SERVICE_DATA_SYNC" will be required, while this permission is not actually being used.

The solution that comes to mind is:

  • Do not add any permission request on Notifee's AndroidManifest and add a must to do point on docs.

  • Or, add in the docs, that if the "dataSync" type is not used, AndroidManifest must include: <uses-permission tools:node="remove" android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> to remove the unused permission request.

@pierguinzani

This comment was marked as duplicate.

@nateshmbhat

This comment was marked as duplicate.

@santhoshvai
Copy link
Contributor Author

@josegiufrida what you said makes a lot of sense to me.. I will update the docs accordingly in this PR

@pke
Copy link

pke commented Aug 9, 2024

The deadline for Android release to target SDK 34 is fast approaching (End of August). This PR is required for all notifee apps to run properly.
Any problems merging this quickly?

  • Or, add in the docs, that if the "dataSync" type is not used, AndroidManifest must include: <uses-permission tools:node="remove" android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> to remove the unused permission request.

@josegiufrida Will this be enough of a fix for now until this PR is merged to be able to run on Android 14?

@FurankuSQ
Copy link

How can we use this branch version of lib' until PR is merged ?

@zungx
Copy link

zungx commented Aug 27, 2024

it seems this one will not work when we start the foreground service from the background.

Foreground service started from background can not have location/camera/microphone access: service my.app/app.notifee.core.ForegroundService

java.lang.RuntimeException: Unable to start service app.notifee.core.ForegroundService@8a6244d with Intent { act=app.notifee.core.ForegroundService.START cmp=my.app/app.notifee.core.ForegroundService (has extras) }: java.lang.SecurityException: Starting FGS with type microphone callerApp=ProcessRecord{5f4ee07 13705:my.app/u0a418} targetSDK=34 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_MICROPHONE] any of the permissions allOf=false [android.permission.CAPTURE_AUDIO_HOTWORD, android.permission.CAPTURE_AUDIO_OUTPUT, android.permission.CAPTURE_MEDIA_OUTPUT, android.permission.CAPTURE_TUNER_AUDIO_INPUT, android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT, android.permission.RECORD_AUDIO] and the app must be in the eligible state/exemptions to access the foreground only permission

@santhoshvai
Copy link
Contributor Author

@zungx The error tells you that you dont have permissions to access microphone in the background! Set the foreground types based on what permissions you have

@mzbyszynski mzbyszynski mentioned this pull request Sep 9, 2024
2 tasks
@mikehardy
Copy link
Collaborator

Hey everyone 👋 - I'm looking into this at this very moment

  • The conflict currently visible is related to a publish I just did to clear out the queue of merged-but-unpublished changes, I'm going to push a rebase change that removes that
  • I'm looking in to the conversation here on the new default dataSync thing added in this PR to see what the best solution is so this is clean
  • I'm probably going to update the gradle files etc in a separate commit so that's cleanly separated from the new feature

But I like the fundamental approach - the basic idea of removing the current always-added foreground service type (which is illegal with new Android permission rules) and creating a new feature of optionally adding specific types is fundamentally sound, it looks like the right way to go

So after a bit of cleanup etc this should be good to merge, hopefully pretty shortly 🚂

@invertase invertase deleted a comment from amjadbouhouch Sep 11, 2024
@invertase invertase deleted a comment from AbhayRudani Sep 11, 2024
@invertase invertase deleted a comment from whalesnetwork Sep 11, 2024
@invertase invertase deleted a comment from owaisansarii Sep 11, 2024
@invertase invertase deleted a comment from santhoshvai Sep 11, 2024
@invertase invertase deleted a comment from ddematheu Sep 11, 2024
@santhoshvai
Copy link
Contributor Author

santhoshvai commented Sep 11, 2024

Hey @mikehardy , thanks a lot for checking this one, I think its best to update the default type to shortService

It doesn't create a problem in google side as no permission is required for adding it. And I can remove the dataSync default.

@mikehardy
Copy link
Collaborator

mikehardy commented Sep 11, 2024

@santhoshvai

Hey @mikehardy , thanks a lot for checking this one, I think its best can update the default type to shortService

Based on the conversation that does seem like the best option, but I want to read all the related android developer documentation first

Please don't worry about updating the PR for a moment - as maintainer I have permission to edit the PR and I am going to do so locally then push it, so as a collaboration item our changes may collide and I would clobber your changes - I don't want you to waste any time making changes that will be clobbered before I push to the PR :-)

[update - nearly there - did the initial push that cleans up quite a few items, just a couple more to go + related pushes...]

Copy link

codecov bot commented Sep 11, 2024

Codecov Report

Attention: Patch coverage is 64.28571% with 10 lines in your changes missing coverage. Please review.

Project coverage is 77.08%. Comparing base (5031a09) to head (02f617f).
Report is 7 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1050      +/-   ##
==========================================
- Coverage   77.29%   77.08%   -0.21%     
==========================================
  Files          32       32              
  Lines        1699     1727      +28     
  Branches      572      579       +7     
==========================================
+ Hits         1313     1331      +18     
- Misses        336      395      +59     
+ Partials       50        1      -49     

required for new foreground service symbols, which are required for Android 14 compatibility
santhoshvai and others added 2 commits September 11, 2024 14:08
BREAKING CHANGE: foreground service users must manually add Android permissions for Android 14+

requires android compileSdk of 34 or greater for new symbols to be available

Android 14+ require foreground services to be strongly typed with specific permissions requested
in the AndroidManifest and specified by the application. You are required to add the correct
permission for the type of service you are using, and then declare it + justify the usage in
the Google Play Store if you need foreground services
Copy link
Collaborator

@mikehardy mikehardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright!

I want to be really quick to mention that the fundamental idea here (and the implementation of the actual feature) was sound and well done, huge thanks to @santhoshvai

I made a big pile of changes but they were all technicalities - lint formatting, minimizing the android build changes to be just a switch to the compileSdk (so as not to have scope creep here on the full set of changes there, they are non-trivial!), etc

Those ones I teased out into separate commits so that the main idea was in one commit and it was easy to see how it worked

I added one thing which is a new Android 15 foreground service type, as a follow-on commit

@mikehardy mikehardy added the pending-merge Waiting on CI or question responses to merge, but otherwise ready label Sep 11, 2024
@mikehardy mikehardy merged commit 4c9d558 into invertase:main Sep 11, 2024
13 of 15 checks passed
@mikehardy mikehardy removed the pending-merge Waiting on CI or question responses to merge, but otherwise ready label Sep 11, 2024
@mikehardy
Copy link
Collaborator

released! https://github.com/invertase/notifee/blob/main/docs-react-native/react-native/docs/release-notes.md#900

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Android API 34: Crash issue Document Android 14 behavior changes for foreground services