ไลบรารีสำหรับเข้าถึงอุปกรณ์เก็บข้อมูล USB (ไดรฟ์ปากกา, HDD ภายนอก, เครื่องอ่านการ์ด) โดยใช้ 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 สิ่งนี้ใช้ไลบรารี libusb แทน API โฮสต์ USB ของ Android สำหรับการสื่อสารระดับต่ำกับอุปกรณ์จัดเก็บข้อมูล 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 หากคุณไม่มีข้อกำหนดพิเศษ คุณสามารถเลือกได้ 1 รายการ ซึ่งไม่น่าจะสร้างความแตกต่างมากนัก
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
ห้องสมุดได้รับการพัฒนาโดย Mr. Jahnen โดยเป็นส่วนหนึ่งของวิทยานิพนธ์ระดับปริญญาตรีของเขาในปี 2014 ห้องสมุดนี้เป็นหัวข้อย่อยของหัวข้อวิจัย "Secure Copy Protection for Mobile Apps" โดย Mr. Kannengießer สามารถดาวน์โหลดเอกสารวิทยานิพนธ์ฉบับเต็มได้ที่นี่
Libaums - ไลบรารีสำหรับเข้าถึงอุปกรณ์จัดเก็บข้อมูล USB
ใบอนุญาต: Apache 2.0 (ดูรายละเอียดในใบอนุญาต.txt)
ผู้แต่ง: Magnus Jahnen, [email protected] ที่ปรึกษา: Nils Kannengießer, nils.kannengiesser ที่ tum.de
หัวหน้างาน: Prof. Uwe Baumgarten, baumgaru จาก in.tum.de
มหาวิทยาลัยเทคนิคมิวนิค (TUM)
Lehrstuhl/Fachgebiet für Betriebssysteme
www.os.in.tum.de