Rendre visibles des fichiers et dossiers créés sur un appareil sous Android depuis Windows et Mac avec une connexion USB MTP

Ce problème pourra dire qu'il m'aura bien pris la tête : déjà pour comprendre ce qu'il se passait et ensuite pour comprendre la multitude de résultats sur les forums et moteurs de recherche de questions posées par des développeurs Java / Android devant le même problème.

Pour une application, je devais créer des fichiers et les mettre à disposition sur le dossier /Download du périphérique sous Android connecté à un PC sous Windows. L'idée était ensuite de permettre aux utilisateurs (ou à un programme exécutable) d'aller chercher ces fichiers pour les traiter avec le logiciel adéquat.

Il se trouve que lorsqu'on crée des fichiers dans l'arborescence d'un terminal (smartphone ou autre) sous Android, par défaut, ce fichier (ou ce dossier) n'est pas disponible de l'extérieur. Il faut attendre que le scanner de média s'active, les voit, et les signale. Hors on ne maîtrise pas ses déclenchements. Il y avait une autre solution : redémarrer le terminal car le scanner s'active au démarrage, mais voilà, la manipulation n'est quand même pas top dans un environnement de production dont on ne maîtrise pas les utilisateurs. C'est source de problèmes et d'appels à la hotline, ce qu'il faut à tout prix limiter.

En cherchant bien, on tombe sur une autre solution : déclencher le référencement des fichiers que l'on veut à la demande. Il faut pour celà appeler un intent par l'intermédiaire d'un broadcast. une fois qu'on a compris ça et trouvé les bonnes unités à inclure dans le projet, ça donne ça :

unit u_android_media_scanner;

// Cette unité Delphi contient des procedures à utiliser sous Android lorsqu'on
// désire donner accès en USB (MTP) à des fichiers créés depuis une application
// (c) 2016 Patrick Prémartin / Olf Software
//
// Liste des mises à jour :
// 16/06/2016, Patrick Prémartin : mise en production de la version initiale

interface

/// <summary>Add a file to the media files cache.</summary>
/// <para>Call it after creating the file you want to share with USB connected device.</para>
/// <param name="filename">absolute path + name of the file to add</param>
procedure android_media_scanner_add_file(filename: string);

/// <summary>Add a folder to the media files cache</summary>
/// <para>Call it after creating the folder you want to share with USB connected device.</para>
/// <param name="foldername">absolute path + name of the folder to add</param>
procedure android_media_scanner_add_folder(foldername: string);

implementation

{$IFDEF ANDROID}
uses AndroidApi.JNI.GraphicsContentViewText, AndroidApi.JNI.App,
  AndroidApi.JNI.Net, AndroidApi.Helpers;
{$ENDIF}

procedure android_media_scanner_add_file(filename: string);
{$IFDEF ANDROID}
var
  Intent: JIntent;
{$ENDIF}
begin
{$IFDEF ANDROID}
  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_MEDIA_SCANNER_SCAN_FILE);
  Intent.setData(StrToJURI('file://' + filename));
  TAndroidHelper.Activity.sendBroadcast(Intent);
{$ENDIF}
end;

procedure android_media_scanner_add_folder(foldername: string);
{$IFDEF ANDROID}
var
  Intent: JIntent;
{$ENDIF}
begin
{$IFDEF ANDROID}
  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_MEDIA_MOUNTED);
  Intent.setData(StrToJURI('file://' + foldername));
  TAndroidHelper.Activity.sendBroadcast(Intent);
{$ENDIF}
end;

end.

Ce code a été testé sous Delphi 10.1 Berlin. J'ignore s'il fonctionnera sur une version Seattle ou précédente car les noms des unités ont changé à plusieurs reprises pour Firemonkey et par conséquent il y aura peut-être des adaptations à faire.


Mug Chinese New Year 2023 : year of the rabbitMug Pascal case in Alexandrie