Android Privacy and Permission Best Practices: How to Prepare for Stricter 2026 Controls
I submitted my app to the Play Store and got rejected. The reason? “Inconsistent data disclosures” and “improper permission handling.” I thought I was following best practices - I asked for permissions at launch, displayed a nice splash screen, and documented everything in my privacy policy.
But apparently, that’s not enough anymore. Android’s 2026 privacy controls are much stricter, and the Play Store now uses AI-driven policy enforcement. Apps that worked fine last year are suddenly getting flagged for permission issues.
After digging through documentation and fixing my app, I figured out what I was doing wrong. Here’s what I learned about Android permission best practices for 2026.
The Problem: Permission Flow Mistakes
My app was doing three things that got flagged:
- Requesting all permissions at app launch - Users saw a wall of permission requests before they even understood what the app did
- Running background location without proper foreground service notification - The app tracked location silently in the background
- Inconsistent data disclosures - My privacy policy said “we use location for navigation” but the app metadata said “location for weather”
Each of these is now a Play Store violation.
Your app requests permissions that are not clearly justifiedby the declared functionality. Specifically:- Background location access without visible foreground service- Permission requests at app start without user context- Data disclosure mismatch between app metadata and actual usageWhy This Matters Now
Android’s enforcement has changed. It’s no longer just about whether your code works - it’s about whether your permission flows match your documented behavior.
Old approach: New requirements:--------------------------------|--------------------------------Request permissions at launch | Request at moment of useBackground location silently | Visible foreground notificationGeneric privacy policy | Specific data disclosuresSelf-declared functionality | AI-verified consistencyThe Play Store now compares your declared data usage against actual SDK behavior. If you use a third-party SDK that performs hidden tracking, you’re responsible for disclosing it - even if you didn’t know it was happening.
Mistake #1: Permission Requests at App Launch
I had this in my main activity:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
// BAD: Request everything at start ActivityCompat.requestPermissions( this, arrayOf( ACCESS_FINE_LOCATION, CAMERA, READ_CONTACTS, WRITE_EXTERNAL_STORAGE ), PERMISSION_REQUEST_CODE )}Users saw four permission dialogs before the app even showed its main screen. Most people just denied everything because they had no context.
The Fix: Request at Moment of Use
Each permission should be requested when the user triggers the feature that needs it:
class MapActivity : AppCompatActivity() {
private fun showUserLocation() { when { // Already granted ContextCompat.checkSelfPermission( this, ACCESS_FINE_LOCATION ) == PERMISSION_GRANTED -> { startLocationUpdates() }
// Show rationale first ActivityCompat.shouldShowRequestPermissionRationale( this, ACCESS_FINE_LOCATION ) -> { showPermissionRationaleDialog( message = "Location is needed to show your position on the map", onAccept = { requestLocationPermission() } ) }
// First time - just request else -> { requestLocationPermission() } } }
private fun requestLocationPermission() { ActivityCompat.requestPermissions( this, arrayOf(ACCESS_FINE_LOCATION), LOCATION_REQUEST_CODE ) }}The key difference: the user has already clicked “Show My Location” before the permission request appears. They understand the context.
Building a Rationale Dialog
When the user has denied permission once, Android recommends showing an explanation:
fun showPermissionRationaleDialog( message: String, onAccept: () -> Unit) { AlertDialog.Builder(this) .setTitle("Permission Required") .setMessage(message) .setPositiveButton("Grant Permission") { _, _ -> onAccept() } .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() } .show()}I reuse this dialog for different permissions, passing different messages:
Location: "Location is needed to show your position on the map"Camera: "Camera access is required to scan QR codes"Contacts: "Contacts permission lets you share with friends"Mistake #2: Background Location Without Foreground Service
My app tracked location in a background service but didn’t show any notification. Users had no idea their location was being tracked.
class LocationService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // BAD: No notification, silent tracking startLocationTracking() return START_STICKY }}This worked on older Android versions. But starting with Android 14, background location requires a visible foreground service with a notification.
The Fix: Foreground Service Declaration
First, declare the service type in your manifest:
<service android:name=".LocationTrackingService" android:foregroundServiceType="location" android:exported="false" />Then start the service with a notification:
class LocationTrackingService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val notification = createNotification()
// Start as foreground service with type startForeground( NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION )
startLocationTracking() return START_STICKY }
private fun createNotification(): Notification { return NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Location Tracking Active") .setContentText("Your location is being tracked for navigation") .setSmallIcon(R.drawable.ic_location) .setPriority(NotificationCompat.PRIORITY_LOW) .build() }}The notification must be visible within 5 seconds of starting the foreground service. If you don’t show it, Android will crash your app.
Mistake #3: Inconsistent Data Disclosures
My privacy policy said one thing, but my app metadata said another. This inconsistency got flagged during the automated review.
Privacy policy: "We use location for weather updates"App metadata: "Location required for navigation features"Actual usage: Location SDK also tracks for advertisingI hadn’t reviewed the third-party SDKs I was using. One of them was collecting location data for ad targeting - something I never disclosed.
The Fix: Complete Data Safety Documentation
The Play Store’s Data Safety section requires you to disclose:
1. What data you collect2. How you use each data type3. Whether data is shared with third parties4. Whether data is encrypted5. Whether users can request deletionI created a table mapping each permission to its usage:
Permission | My usage | Third-party SDK usage--------------------|------------------|----------------------ACCESS_FINE_LOCATION| Navigation only | Ad targeting (needs disclosure)CAMERA | QR scanning | NoneREAD_CONTACTS | Sharing feature | NoneThe ad targeting disclosure was missing. I had to either:
- Remove the SDK that tracked for ads
- Add the disclosure to my Data Safety section
I chose option 1 - I didn’t want my users’ location used for ads.
The Permission Flow Diagram
Here’s how a proper permission request flow should work:
User action App response------------------------|---------------------------Tap "Show My Location" | | Check if permission granted | If yes: Show location | If no: Check if rationale needed | | [Rationale needed?] | Yes: Show dialog explaining why | User accepts: Request permission | User cancels: Don't request again | | No: First request | Request permission |Permission dialog shown | | User grants: Show location | User denies: Show manual enable optionThe user drives the flow. Permission requests happen only when needed, with clear context.
Common SDK Issues
Many rejections come from third-party SDKs doing things you didn’t expect:
SDK type | Known issues----------------------|--------------------------------Analytics SDKs | May collect location for targetingAd SDKs | Often track across appsSocial login SDKs | May collect device identifiersMap SDKs | Some track location historyPush notification SDKs| May collect usage patternsI now audit each SDK before adding it:
- Check the SDK’s privacy policy
- Review what permissions it requests
- Test with network logging to see actual data flows
- Document everything in my Data Safety section
Permission Best Practices Summary
After fixing my app, here’s what I now follow:
✓ Request permissions at the moment of use✓ Show rationale after first denial✓ Use foreground services with notifications for background work✓ Declare foreground service types in manifest✓ Audit all third-party SDKs for hidden tracking✓ Document actual data usage (not just intended usage)✓ Keep privacy policy and app metadata consistent✓ Provide users with data deletion optionsThe enforcement is automated. If your declared behavior doesn’t match your actual behavior, you’ll get flagged - regardless of whether you knew about the discrepancy.
What Got My App Approved
After implementing these changes:
- Permission requests moved to feature-trigger points
- Background location now shows a foreground notification
- Removed the ad-tracking SDK
- Updated Data Safety section with accurate disclosures
- Privacy policy matches app metadata
Splash screen: No permission requestsMain screen: User explores app featuresFeature trigger: Permission request with contextBackground work: Visible foreground notificationData disclosure: Matches actual SDK behaviorThe second submission passed review within 24 hours.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Android 12 behavior changes - PendingIntent mutability
- 👨💻 Request runtime permissions
- 👨💻 Foreground service types
- 👨💻 Play Store Data Safety section
- 👨💻 Android privacy and security best practices
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments