Skip to content

Instantly share code, notes, and snippets.

@shlomoweb1
Last active June 22, 2023 23:37
Show Gist options
  • Select an option

  • Save shlomoweb1/8ff6bcc9121c31634cca4887d3c215de to your computer and use it in GitHub Desktop.

Select an option

Save shlomoweb1/8ff6bcc9121c31634cca4887d3c215de to your computer and use it in GitHub Desktop.
Java Android Permission with fallback up to android Q, React Native
// Top-level build file where you can add configuration options common to all sub-projects/modules.
// https://apilevels.com/
buildscript {
ext {
buildToolsVersion = "33.0.0"
minSdkVersion = 26
compileSdkVersion = 33
targetSdkVersion = 26
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("com.google.gms:google-services:4.3.15")
}
}
package com.myApp;
import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import java.util.List;
import com.myApp.permissions.PermissionsModulePackage; // Import the PermissionsModulePackage
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new DefaultReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Add PermissionsModulePackage to the packages list
packages.add(new PermissionsModulePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load();
}
ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
}
package com.myApp.permissions;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PermissionsModule extends ReactContextBaseJavaModule {
private static final String MODULE_NAME = "myAppPermission";
private static final int PERMISSION_REQUEST_CODE = 1;
private Callback permissionCallback;
public PermissionsModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@NonNull
@Override
public String getName() {
return MODULE_NAME;
}
// Method to request permissions
@ReactMethod
public void requestPermissions(ReadableArray permissions, Callback callback) {
permissionCallback = callback;
List<String> pendingPermissions = filterPermissions(convertReadableArrayToStringArray(permissions));
String[] pendingPermissionsArray = pendingPermissions.toArray(new String[0]);
if (pendingPermissionsArray.length > 0) {
// Request permissions
ActivityCompat.requestPermissions(getCurrentActivity(), pendingPermissionsArray, PERMISSION_REQUEST_CODE);
} else {
// No permissions to request, return results
WritableArray grantedPermissions = new WritableNativeArray();
WritableArray deniedPermissions = new WritableNativeArray();
for (String permission : convertReadableArrayToStringArray(permissions)) {
if (ContextCompat.checkSelfPermission(getReactApplicationContext(), permission) == PackageManager.PERMISSION_GRANTED) {
// Permission granted
grantedPermissions.pushString(permission);
} else {
// Permission denied
deniedPermissions.pushString(permission);
}
}
permissionCallback.invoke(grantedPermissions, deniedPermissions);
permissionCallback = null;
}
}
// Helper method to convert ReadableArray to String[]
private String[] convertReadableArrayToStringArray(ReadableArray readableArray) {
String[] stringArray = new String[readableArray.size()];
for (int i = 0; i < readableArray.size(); i++) {
stringArray[i] = readableArray.getString(i);
}
return stringArray;
}
// Method to check permissions without requesting
@ReactMethod
public void checkPermissions(ReadableArray permissions, Callback callback) {
List<String> filteredPermissions = filterPermissionsByAPIVersion(convertReadableArrayToStringArray(permissions));
WritableArray grantedPermissions = new WritableNativeArray();
WritableArray deniedPermissions = new WritableNativeArray();
for (String permission : filteredPermissions) {
int permissionStatus = ContextCompat.checkSelfPermission(getReactApplicationContext(), permission);
if (permissionStatus == PackageManager.PERMISSION_GRANTED) {
// Permission granted
grantedPermissions.pushString(permission);
} else {
// Permission denied or not granted
WritableMap deniedPermission = Arguments.createMap();
deniedPermission.putString("permission", permission);
deniedPermission.putString("reason", String.valueOf(permissionStatus));
deniedPermissions.pushMap(deniedPermission);
}
}
callback.invoke(grantedPermissions, deniedPermissions);
}
private List<String> filterPermissionsByAPIVersion(String[] permissions) {
List<String> filteredPermissions = new ArrayList<>();
for (String permission : permissions) {
// Apply your filtering logic based on the Android API version
if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
if(isAndroidQOrAbove()){
filteredPermissions.add(permission);
}
// Skip adding the permission if not on Android Q or above
continue;
} else if (permission.equals(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
if(isAndroidROrAbove()){
filteredPermissions.add(permission);
}
// Skip adding the permission if not on Android R or above
continue;
} else if (permission.equals(Manifest.permission.POST_NOTIFICATIONS)) {
if(isAndroidTiramisuOrAbove()){
filteredPermissions.add(permission);
}
// Skip adding the permission if not on Android Tiramisu or above
continue;
} else {
// Permission doesn't match any filtering condition, include it in the final result
filteredPermissions.add(permission);
}
}
return filteredPermissions;
}
// Filter out permissions that are already granted or API level to low
private List<String> filterPermissions(String[] permissions) {
Set<String> pendingPermissions = new HashSet<>();
for (String permission : permissions) {
boolean hasPermission = ContextCompat.checkSelfPermission(getReactApplicationContext(), permission) == PackageManager.PERMISSION_GRANTED;
if (!hasPermission) {
pendingPermissions.add(permission);
} else {
// Remove if already granted
pendingPermissions.remove(permission);
}
}
// Apply additional filtering based on Android API version [remove uneeded perrmision per API version]
List<String> filteredPermissions = filterPermissionsByAPIVersion(pendingPermissions.toArray(new String[0]));
return filteredPermissions;
}
// Handle the result of permission requests
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_CODE) {
WritableArray grantedPermissions = new WritableNativeArray();
WritableArray deniedPermissions = new WritableNativeArray();
for (int i = 0; i < permissions.length; i++) {
String permission = permissions[i];
int grantResult = grantResults[i];
if (grantResult == PackageManager.PERMISSION_GRANTED) {
// Permission granted
grantedPermissions.pushString(permission);
} else {
// Permission denied
WritableMap deniedPermission = Arguments.createMap();
deniedPermission.putString("permission", permission);
deniedPermission.putString("reason", String.valueOf(grantResult));
deniedPermissions.pushMap(deniedPermission);
}
}
// Invoke the permission callback with the results
permissionCallback.invoke(grantedPermissions, deniedPermissions);
permissionCallback = null;
}
}
// Check API level 29 (Android 10) or above
private boolean isAndroidQOrAbove() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
}
// Check API level 30 (Android 11) or above
private boolean isAndroidROrAbove() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
}
// Check API level 33 (Android 13) or above
private boolean isAndroidTiramisuOrAbove(){
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
}
}
package com.myApp.permissions;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.ReactPackage;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class PermissionsModulePackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.asList(new NativeModule[]{
new PermissionsModule(reactContext)
});
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment