Библиотека для доступа к USB-устройствам хранения данных (флеш-накопителям, внешним жестким дискам, устройствам чтения карт) с использованием Android USB Host API. В настоящее время он поддерживает набор команд SCSI и файловую систему FAT32.
Библиотеку можно включить в ваш проект следующим образом:
implementation 'me.jahnen.libaums:core:0.10.0'
Если вам нужен модуль HTTP или поставщика хранилища:
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)
}
Ваше приложение должно получить разрешение от пользователя во время выполнения, чтобы иметь возможность связываться с устройством. Из UsbMassStorageDevice
вы можете получить для этого базовый android.usb.UsbDevice
.
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);
Для получения дополнительной информации о разрешениях ознакомьтесь с документацией 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 ();
Если вы довольно часто получаете следующую ошибку (в основном под Android 9.0 Pie):
java.io.IOException: Could not write to device, result == -1 errno 0 null
или что-то подобное, вы можете попробовать модуль libusb. Вместо API USB-хоста Android используется библиотека libusb для низкоуровневой связи с запоминающим устройством USB.
см. обсуждения: #209 #237 #242
Обратите внимание , что libusb распространяется под лицензией LGPL, которая отличается от лицензии, под которой лицензируется этот проект! Это может иметь некоторые недостатки или дополнительную работу для приложений с закрытым исходным кодом, см. здесь: https://xebia.com/blog/the-lgpl-on-android/
Обычно сторонние приложения не имеют доступа к файлам на запоминающем устройстве, если система Android монтируется (обычно это поддерживается на новых устройствах, в 2014 году такой поддержки не было), устройство или это приложение само интегрирует эту библиотеку. . Чтобы решить эту проблему, есть два дополнительных модуля, обеспечивающих доступ к другим приложениям. Один использует функцию Storage Access Framework Android (уровень API >= 19), а другой запускает HTTP-сервер, например, для загрузки или потоковой передачи видео или изображений.
libaums в настоящее время поддерживает две разные библиотеки HTTP-сервера.
Вы можете довольно легко развернуть сервер, вам просто нужно выбрать реализацию HTTP-сервера. Если у вас нет особых требований, вы можете просто выбрать один, это не должно иметь большого значения.
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()
Предоставленный вами файл может быть либо реальным файлом, либо каталогом:
Если вы хотите иметь доступ к этим файлам, когда ваше приложение работает в фоновом режиме, вам следует реализовать для этого службу. В модуле httpserver
доступен пример. Вы можете использовать его, но вам следует создать его подкласс или создать свой собственный, чтобы адаптировать его к своим потребностям.
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 )
}
Дополнительные сведения см. в примере приложения.
Чтобы узнать больше об этом, посетите: https://developer.android.com/guide/topics/providers/document-provider.html.
Чтобы интегрировать этот модуль в ваше приложение, все, что вам нужно сделать, это добавить определение в ваш 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 >
После этого приложения, использующие Storage Access Framework, смогут получить доступ к файлам USB-накопителя.
app/
вы можете найти пример приложения, использующего библиотеку.UsbFile.setLength(long)
. В противном случае ClusterChain придется увеличивать для каждого вызова записи. Это очень неэффективно.FileSystem.getChunkSize()
в качестве размера буфера, поскольку это соответствует размерам блоков, которые используют диски. Все остальное тоже скорее всего снижение производительности.UsbFileStreamFactory
. Библиотека была разработана г-ном Яненом в рамках его бакалаврской диссертации в 2014 году. Это подтема исследования г-на Канненгиссера «Надежная защита от копирования для мобильных приложений». Полный текст дипломной работы можно скачать здесь.
Libaums — библиотека для доступа к USB-накопителям
Лицензия: Apache 2.0 (подробности см. в файле License.txt)
Автор: Магнус Янен, [email protected] Консультант: Нильс Канненгисер, nils.kannengiesser на tum.de
Руководитель: профессор Уве Баумгартен, baumgaru in.tum.de
Технический университет Мюнхена (ТУМ)
Lehrstuhl/Fachgebiet für Betriebssysteme
www.os.in.tum.de