Outils pour utilisateurs

Outils du site


lang:android:permission

Demande de permissions

Demande explicites pour permissions multiples

private ActivityResultLauncher<String[]> requestPermissionLauncher = registerForActivityResult(
  new ActivityResultContracts.RequestMultiplePermissions(),
  isGranted -> {
    if (!isGranted.containsValue(false)) {
      // Tous les accès sont bons.
    }
  }
);
 
String[] ask_permission = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
  Manifest.permission.READ_EXTERNAL_STORAGE};
 
requestPermissionLauncher.launch(ask_permission);

Requesting runtime permissions using new ActivityResult API Archive du 06/07/2020 le 26/09/2022

Demande d'accès sur événements

Avec quelques spécificités sur l'USB.

  • Code Kotlin
private lateinit var mPermissionIntent: PendingIntent
private lateinit var mUsbManager: UsbManager
 
private val ACTION_USB_PERMISSION = "com.class.name.USB_PERMISSION"
private val mUsbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
    if (device == null) {
      return
    }
 
    when (intent.action) {
      ACTION_USB_PERMISSION -> {
        synchronized(this) {
          if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
          } else {
            // Denied
          }
        }
      }
      UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
        if (!mUsbManager.hasPermission(device)) {
          mUsbManager.requestPermission(device, mPermissionIntent)
        } else {
          // Denied
        }
      }
      UsbManager.ACTION_USB_DEVICE_DETACHED -> {
        // Detached
      }
    }
  }
}
 
override fun onCreate(savedInstanceState: Bundle?) {
  mUsbManager = getSystemService(Context.USB_SERVICE) as UsbManager
 
  mPermissionIntent =
    PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0);
  val filter = IntentFilter()
  filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
  filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
  filter.addAction(ACTION_USB_PERMISSION)
  registerReceiver(mUsbReceiver, filter)
}
  • app\src\main\AndroidManifest.xml

Déclarer la liste des droits nécessaires.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.androidusbhost"
  android:versionCode="1"
  android:versionName="1.0" >
  <application
    <activity
      <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
      </intent-filter>
      <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
        android:resource="@xml/device_filter" />
      <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
      </intent-filter>
    </activity>
  </application>
</manifest>
  • Filtrer les devices USB autorisés dans app\src\main\res\xml\device_filter.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Accept all device VID/PID combinations -->
    <usb-device />
</resources>

Permission se demandant via une fenêtre dédiée et non une simple popup

Exemple avec MANAGE_EXTERNAL_STORAGE.

  • Avant API 30

Il faut ajouter android:requestLegacyExternalStorage="true" à AndroidManifest.xml.

  • A partir de l'API 30

Cela se fait en ouvrant une fenêtre dédiée à la modification des droits. On commence par vérifier si on a les droits avant. Puis on vérifie si on a les droits à la fermeture de la fenêtre.

Ne pas appelé registerForActivityResult depuis le constructeur mais depuis onCreate. Si la vue est recréée (onCreate), l'intent est unregister. Il faut donc le register à nouveau.

Le composant ActivityResultLauncher ne doit pas être appelé depuis onCreate mais après.

Note: You must call registerForActivityResult() before the fragment or activity is created; you cannot launch the ActivityResultLauncher until the fragment or activity's Lifecycle has reached CREATED.Getting a result from an activity Archive du 20/09/2022 le 17/01/2023

private ActivityResultLauncher<Intent> requestManageAllFilesLauncher;
 
public void onCreate(Bundle savedInstanceState)
  requestManageAllFilesLauncher = registerForActivityResult(
  new ActivityResultContracts.StartActivityForResult(),
    result -> {
      if (Environment.isExternalStorageManager()) {
        // Accès validé.
      }
    }
);
 
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
  Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
  Uri uri = Uri.fromParts("package", getPackageName(), null);
  intent.setData(uri);
  requestManageAllFilesLauncher.launch(intent);
} else {
  // OK
}

Message d'erreur si le composant a été unregister dû à un nouveau cycle de vie : java.lang.IllegalStateException: Attempting to launch an unregistered ActivityResultLauncher with contract androidx.activity.result.contract.ActivityResultContracts$StartActivityForResult@27807b and input Intent { act=android.intent.action.OPEN_DOCUMENT_TREE }. You must ensure the ActivityResultLauncher is registered before calling launch().

Creating a custom contract Archive du 20/09/2022 le 26/09/2022

Autorisation avec adb

Pour les tests, il peut être nécessaire d'activer certaines autorisations sans interaction avec l'utilisateur.

adb shell appops set --uid com.package MANAGE_EXTERNAL_STORAGE allow

Pour avoir la liste des permissions, lancer :

adb shell 'pm list permissions | sort'

Permission des dossiers

  • Carte SD ou /storage/emulated

Ne doit servir que pour stocker des données. Il n'est pas possible d'y stocker des exécutables. Le dossier est monté en noexec.

  • Dossier home de l'application ou /data/data

Ne doit servir que pour stocker des données spécifiques à chaque application. Il n'est pas possible d'y stocker des exécutables.

Pour exécuter des binaires externes, il faut les embarquer dans l'apk.

Removed execute permission for app home directory Archive du 19/09/2022 le 27/09/2022

lang/android/permission.txt · Dernière modification : 2023/04/12 13:37 de root