Une bibliothèque pour accéder aux périphériques de stockage de masse USB (clés USB, disques durs externes, lecteurs de cartes) à l'aide de l'API Android USB Host. Actuellement, il prend en charge le jeu de commandes SCSI et le système de fichiers FAT32.
La bibliothèque peut être incluse dans votre projet comme ceci :
implementation 'me.jahnen.libaums:core:0.10.0'
Si vous avez besoin du module HTTP ou du fournisseur de stockage :
implementation 'me.jahnen.libaums:httpserver:0.6.2'
implementation 'me.jahnen.libaums:storageprovider:0.6.2'
UsbMassStorageDevice [] devices = UsbMassStorageDevice . getMassStorageDevices ( this /* Context or Activity */ );
for ( UsbMassStorageDevice device : devices ) {
// before interacting with a device you need to call init()!
device . init ();
// Only uses the first partition on the device
FileSystem currentFs = device . getPartitions (). get ( 0 ). getFileSystem ();
Log . d ( TAG , "Capacity: " + currentFs . getCapacity ());
Log . d ( TAG , "Occupied Space: " + currentFs . getOccupiedSpace ());
Log . d ( TAG , "Free Space: " + currentFs . getFreeSpace ());
Log . d ( TAG , "Chunk size: " + currentFs . getChunkSize ());
}
val devices = UsbMassStorageDevice .getMassStorageDevices( this /* Context or Activity */ )
for (device in devices) {
// before interacting with a device you need to call init()!
device. init ()
// Only uses the first partition on the device
val currentFs = device.partitions[ 0 ].fileSystem
Log .d( TAG , " Capacity: " + currentFs.capacity)
Log .d( TAG , " Occupied Space: " + currentFs.occupiedSpace)
Log .d( TAG , " Free Space: " + currentFs.freeSpace)
Log .d( TAG , " Chunk size: " + currentFs.chunkSize)
}
Votre application doit obtenir l'autorisation de l'utilisateur au moment de l'exécution pour pouvoir communiquer avec l'appareil. À partir d'un UsbMassStorageDevice
vous pouvez demander au android.usb.UsbDevice
sous-jacent de le faire.
PendingIntent permissionIntent = PendingIntent . getBroadcast ( this , 0 , new Intent ( ACTION_USB_PERMISSION ), 0 );
usbManager . requestPermission ( device . getUsbDevice (), permissionIntent );
val permissionIntent = PendingIntent .getBroadcast( this , 0 , Intent ( ACTION_USB_PERMISSION ), 0 );
usbManager.requestPermission(device.usDevice, permissionIntent);
Pour plus d'informations sur les autorisations, veuillez consulter la documentation Android : https://developer.android.com/guide/topics/connectivity/usb/host.html#permission-d
UsbFile root = currentFs . getRootDirectory ();
UsbFile [] files = root . listFiles ();
for ( UsbFile file : files ) {
Log . d ( TAG , file . getName ());
if (! file . isDirectory ()) {
Log . d ( TAG , file . getLength ());
}
}
UsbFile newDir = root . createDirectory ( "foo" );
UsbFile file = newDir . createFile ( "bar.txt" );
// write to a file
OutputStream os = new UsbFileOutputStream ( file );
os . write ( "hello" . getBytes ());
os . close ();
// read from a file
InputStream is = new UsbFileInputStream ( file );
byte [] buffer = new byte [ currentFs . getChunkSize ()];
is . read ( buffer );
val root = currentFs.rootDirectory
val files = root.listFiles()
for (file in files) {
Log .d( TAG , file.name)
if (file.isDirectory) {
Log .d( TAG , file.length)
}
}
val newDir = root.createDirectory( " foo " )
val file = newDir.createFile( " bar.txt " )
// write to a file
val os = UsbFileOutputStream (file)
os.write( " hello " .toByteArray())
os.close()
// read from a file
val ins = UsbFileInputStream (file)
val buffer = ByteArray (currentFs.chunkSize)
ins.read(buffer)
OutputStream os = UsbFileStreamFactory . createBufferedOutputStream ( file , currentFs );
InputStream is = UsbFileStreamFactory . createBufferedInputStream ( file , currentFs );
// Don't forget to call UsbMassStorageDevice.close() when you are finished
device . close ();
Si vous obtenez assez souvent l’erreur suivante (principalement sous Android 9.0 Pie) :
java.io.IOException: Could not write to device, result == -1 errno 0 null
ou quelque chose de similaire, vous voudrez peut-être essayer le module libusb. Celui-ci utilise, au lieu de l'API hôte USB Android, la bibliothèque libusb pour la communication de bas niveau avec le périphérique de stockage de masse USB.
voir discussions : #209 #237 #242
Notez que libusb est sous licence LGPL, ce qui est différent de la licence sous laquelle ce projet est sous licence ! Cela peut entraîner certains inconvénients ou un travail supplémentaire pour les applications fermées, voir ici : https://xebia.com/blog/the-lgpl-on-android/
Habituellement, les applications tierces n'ont pas accès aux fichiers sur un périphérique de stockage de masse si le système Android est monté (cela est généralement pris en charge sur les appareils plus récents, en 2014, il n'y avait pas de support pour cela) l'appareil ou cette application intègre cette bibliothèque elle-même . Pour résoudre ce problème, il existe deux modules supplémentaires permettant d'accéder à d'autres applications. L'un utilise la fonctionnalité Storage Access Framework d'Android (niveau API >= 19) et l'autre fait tourner un serveur HTTP pour permettre le téléchargement ou le streaming de vidéos ou d'images par exemple.
libaums prend actuellement en charge deux bibliothèques de serveurs HTTP différentes.
Vous pouvez créer un serveur assez facilement, il vous suffit de décider d'une implémentation de serveur HTTP. Si vous n’avez pas d’exigences particulières, vous pouvez en choisir un, cela ne devrait pas faire beaucoup de différence.
UsbFile file = ... // can be directory or file
HttpServer server = AsyncHttpServer ( 8000 ); // port 8000
// or
HttpServer server = NanoHttpdServer ( 8000 ); // port 8000
UsbFileHttpServer fileServer = new UsbFileHttpServer ( file , server );
fileServer . start ();
val file : UsbFile
// can be directory or file
val server = AsyncHttpServer ( 8000 ) // port 8000
// or
val server = NanoHttpdServer ( 8000 ) // port 8000
val fileServer = UsbFileHttpServer (file, server)
fileServer.start()
Le fichier que vous fournissez peut être un fichier réel ou un répertoire :
Si vous souhaitez pouvoir accéder à ces fichiers lorsque votre application est en arrière-plan, vous devez implémenter un service pour cela. Il existe un exemple disponible dans le module httpserver
. Vous pouvez l'utiliser, mais vous devez le sous-classer ou créer le vôtre pour l'adapter à vos besoins.
private UsbFileHttpServerService serverService ;
ServiceConnection serviceConnection = new ServiceConnection () {
@ Override
public void onServiceConnected ( ComponentName name , IBinder service ) {
Log . d ( TAG , "on service connected " + name );
UsbFileHttpServerService . ServiceBinder binder = ( UsbFileHttpServerService . ServiceBinder ) service ;
serverService = binder . getService ();
}
@ Override
public void onServiceDisconnected ( ComponentName name ) {
Log . d ( TAG , "on service disconnected " + name );
serverService = null ;
}
};
@ Override
protected void onCreate ( Bundle savedInstanceState ) {
...
serviceIntent = new Intent ( this , UsbFileHttpServerService . class );
...
}
@ Override
protected void onStart () {
super . onStart ();
startService ( serviceIntent );
bindService ( serviceIntent , serviceConnection , Context . BIND_AUTO_CREATE );
}
private void startHttpServer ( final UsbFile file ) {
...
serverService . startServer ( file , new AsyncHttpServer ( 8000 ));
...
}
private var serverService : UsbFileHttpServerService ? = null
internal var serviceConnection : ServiceConnection = object : ServiceConnection () {
override fun onServiceConnected ( name : ComponentName , service : IBinder ) {
Log .d( TAG , " on service connected $name " )
val binder = service as UsbFileHttpServerService . ServiceBinder
serverService = binder.getService()
}
override fun onServiceDisconnected ( name : ComponentName ) {
Log .d( TAG , " on service disconnected $name " )
serverService = null
}
}
override protected fun onCreate ( savedInstanceState : Bundle ) {
serviceIntent = Intent ( this , UsbFileHttpServerService :: class .java)
}
override protected fun onStart () {
super .onStart()
startService(serviceIntent)
bindService(serviceIntent, serviceConnection, Context . BIND_AUTO_CREATE )
}
Consultez l’exemple d’application pour plus de détails à ce sujet.
Pour en savoir plus sur cette visite : https://developer.android.com/guide/topics/providers/document-provider.html
Pour intégrer ce module dans votre application, la seule chose que vous avez à faire est d'ajouter la définition dans votre AndroidManifest.xml.
< provider
android : name = " me.jahnen.libaums.storageprovider.UsbDocumentProvider "
android : authorities = " me.jahnen.libaums.storageprovider.documents "
android : exported = " true "
android : grantUriPermissions = " true "
android : permission = " android.permission.MANAGE_DOCUMENTS "
android : enabled = " @bool/isAtLeastKitKat " >
< intent-filter >
< action android : name = " android.content.action.DOCUMENTS_PROVIDER " />
</ intent-filter >
</ provider >
Après cela, les applications utilisant Storage Access Framework pourront accéder aux fichiers du périphérique de stockage de masse USB.
app/
vous pouvez trouver un exemple d'application utilisant la bibliothèque.UsbFile.setLength(long)
. Sinon, le ClusterChain doit être augmenté pour chaque appel à écrire. C'est très inefficace.FileSystem.getChunkSize()
comme taille de tampon, car cela correspond aux tailles de bloc utilisées par les lecteurs. Tout le reste est aussi très probablement une diminution des performances.UsbFileStreamFactory
. La bibliothèque a été développée par M. Jahnen dans le cadre de sa thèse de licence en 2014. Il s'agit d'un sous-thème du thème de recherche "Protection sécurisée contre la copie pour les applications mobiles" de M. Kannengießer. Le document complet de la thèse peut être téléchargé ici.
Libaums - Bibliothèque pour accéder aux périphériques de stockage de masse USB
Licence : Apache 2.0 (voir licence.txt pour plus de détails)
Auteur : Magnus Jahnen, [email protected] Conseiller : Nils Kannengießer, nils.kannengiesser sur tum.de
Superviseur : Prof. Uwe Baumgarten, baumgaru chez in.tum.de
Université technique de Munich (TUM)
Lehrstuhl/Fachgebiet für Betriebssysteme
www.os.in.tum.de