مكتبة للوصول إلى أجهزة تخزين 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. يستخدم هذا، بدلاً من واجهة برمجة تطبيقات Android USB host، مكتبة libusb للاتصال منخفض المستوى مع جهاز تخزين USB كبير السعة.
انظر المناقشات: #209 #237 #242
لاحظ أن libusb مرخص بموجب LGPL، وهو يختلف عن الترخيص الذي تم ترخيص هذا المشروع بموجبه! قد يأتي هذا مع بعض العيوب أو العمل الإضافي للتطبيقات مغلقة المصدر، راجع هنا: https://xebia.com/blog/the-lgpl-on-android/
عادةً لا تتمكن تطبيقات الطرف الثالث من الوصول إلى الملفات الموجودة على جهاز تخزين كبير السعة إذا تم تثبيت نظام Android (عادةً ما يكون هذا مدعومًا على الأجهزة الأحدث، في عام 2014 لم يكن هناك دعم لذلك) يدمج الجهاز أو هذا التطبيق هذه المكتبة نفسها . لحل هذه المشكلة، هناك وحدتان إضافيتان لتوفير الوصول إلى التطبيقات الأخرى. يستخدم أحدهما ميزة Storage Access Framework لنظام Android (مستوى واجهة برمجة التطبيقات >= 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
المشرف: البروفيسور أوي بومغارتن، بومغارو في in.tum.de
الجامعة التقنية في ميونيخ (TUM)
Lehrstuhl/Fachgebiet für Betriebssysteme
www.os.in.tum.de