Uygulamanızı içerik URI'leri kullanarak dosya paylaşacak şekilde ayarladıktan sonra, diğer uygulamaların bu dosyalar için istek gönderebilir. Bu isteklere yanıt vermenin bir yolu da diğer uygulamaların çağırabileceği sunucu uygulamasından gelen bir arayüz oluşturur. Bu yaklaşım sayesinde kullanıcıların sunucu uygulamasından bir dosya seçmelerini ve daha sonra seçilen dosyanın içerik URI'si.
Bu derste, uygulamanızda dosya seçimi (Activity
) nasıl oluşturulacağı açıklanmaktadır.
yanıt veren bir reklam öğesi ekler.
Dosya istekleri alma
İstemci uygulamalarından dosya istekleri almak ve içerik URI'si ile yanıt vermek için uygulamanız
bir dosya seçimi Activity
sağlayın. İstemci uygulamaları bunu başlatır
İşlemi içeren bir Intent
ile startActivityForResult()
çağrısı yaparak Activity
ACTION_PICK
. İstemci uygulaması aradığında
startActivityForResult()
, uygulamanız şunları yapabilir:
istemci uygulamasına, kullanıcının seçtiği dosya için içerik URI'si biçiminde bir sonuç döndürür.
İstemci uygulamasında bir dosya isteğini nasıl uygulayacağınızı öğrenmek için Paylaşılan dosya isteğinde bulunma.
Dosya seçimi etkinliği oluşturma
Activity
dosya seçimini ayarlamak için öncelikle
Manifest'inizde Activity
ile birlikte bir intent filtresi
ACTION_PICK
ve
CATEGORY_DEFAULT
ve
CATEGORY_OPENABLE
. MIME türü filtreleri de ekle
diğer uygulamalara sunduğu dosyalar için Google Etiket Yöneticisi'ni kullanabilirsiniz. Aşağıdaki snippet,
yeni Activity
ve intent filtresi:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> ... <application> ... <activity android:name=".FileSelectActivity" android:label="@File Selector" > <intent-filter> <action android:name="android.intent.action.PICK"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.OPENABLE"/> <data android:mimeType="text/plain"/> <data android:mimeType="image/*"/> </intent-filter> </activity>
Kodda dosya seçimi etkinliğini tanımlama
Sonra, mevcut dosyaları gösteren bir Activity
alt sınıfı tanımlayın
dahili depolama alanındaki files/images/
dizinini destekler ve kullanıcının
seçin. Aşağıdaki snippet, bunun nasıl tanımlanacağını gösterir
Activity
ve kullanıcının seçimine yanıt verin:
Kotlin
class MainActivity : Activity() { // The path to the root of this app's internal storage private lateinit var privateRootDir: File // The path to the "images" subdirectory private lateinit var imagesDir: File // Array of files in the images subdirectory private lateinit var imageFiles: Array<File> // Array of filenames corresponding to imageFiles private lateinit var imageFilenames: Array<String> // Initialize the Activity override fun onCreate(savedInstanceState: Bundle?) { ... // Set up an Intent to send back to apps that request a file resultIntent = Intent("com.example.myapp.ACTION_RETURN_FILE") // Get the files/ subdirectory of internal storage privateRootDir = filesDir // Get the files/images subdirectory; imagesDir = File(privateRootDir, "images") // Get the files in the images subdirectory imageFiles = imagesDir.listFiles() // Set the Activity's result to null to begin with setResult(Activity.RESULT_CANCELED, null) /* * Display the file names in the ListView fileListView. * Back the ListView with the array imageFilenames, which * you can create by iterating through imageFiles and * calling File.getAbsolutePath() for each File */ ... } ... }
Java
public class MainActivity extends Activity { // The path to the root of this app's internal storage private File privateRootDir; // The path to the "images" subdirectory private File imagesDir; // Array of files in the images subdirectory File[] imageFiles; // Array of filenames corresponding to imageFiles String[] imageFilenames; // Initialize the Activity @Override protected void onCreate(Bundle savedInstanceState) { ... // Set up an Intent to send back to apps that request a file resultIntent = new Intent("com.example.myapp.ACTION_RETURN_FILE"); // Get the files/ subdirectory of internal storage privateRootDir = getFilesDir(); // Get the files/images subdirectory; imagesDir = new File(privateRootDir, "images"); // Get the files in the images subdirectory imageFiles = imagesDir.listFiles(); // Set the Activity's result to null to begin with setResult(Activity.RESULT_CANCELED, null); /* * Display the file names in the ListView fileListView. * Back the ListView with the array imageFilenames, which * you can create by iterating through imageFiles and * calling File.getAbsolutePath() for each File */ ... } ... }
Dosya seçimine yanıt verme
Uygulamanız, paylaşılan bir dosyayı seçtiğinde hangi dosyanın seçildiğini belirlemeli ve
daha sonra dosya için bir içerik URI'si oluşturabilirsiniz. Activity
,
Kullanıcı bir dosya adını tıkladığında ListView
içindeki kullanılabilir dosyaların listesi
sistem, seçili dosyayı alabileceğiniz onItemClick()
yöntemini çağırır.
Bir dosyanın URI'sini bir uygulamadan diğerine göndermek için bir intent kullanırken
başka birinin kullandığı URI'ları alırken
okuyabiliyor. Android 6.0 (API düzeyi 23) ve sonraki sürümleri çalıştıran cihazlarda bunu yapma
özel
Android'in bu sürümünde izin modelinde yapılan değişiklikler nedeniyle,
READ_EXTERNAL_STORAGE
olmak
tehlikeli izni kapsayan bir açık kaynak belirtin.
Bu noktaları göz önünde bulundurarak,
Uri.fromFile()
,
bazı dezavantajlar içerir. Bu yöntem:
- Profiller arasında dosya paylaşımına izin vermez.
- Uygulamanızda
WRITE_EXTERNAL_STORAGE
. izni. - Alıcı uygulamaların
READ_EXTERNAL_STORAGE
izni. Bu, Gmail gibi bu izne sahip olmayan önemli paylaşım hedeflerinde başarısız olur.
Uri.fromFile()
yerine
diğer uygulamalara izin vermek için URI izinlerini kullanabilirsiniz
belirli URI'lere erişim. file://
URI'lerinde URI izinleri çalışmasa da
Uri.fromFile()
tarafından oluşturulan
İçerik Sağlayıcılarla ilişkili URI'lar üzerinde çalışır. İlgili içeriği oluşturmak için kullanılan
FileProvider
API şunları yapabilir:
bu tür URI'ler oluşturmanıza yardımcı olur. Bu yaklaşım,
bunu harici depolamada ancak niyeti gönderen uygulamanın yerel depolama alanında bulabilirsiniz.
onItemClick()
uygulamasında bir
File
nesnesini ayarlayın ve bunu bağımsız değişken olarak
getUriForFile()
ve
ilgili yetki belgesinde belirttiğiniz
FileProvider
için <provider>
öğesi.
Sonuçta ortaya çıkan içerik URI'si; yetkiliyi, yani dosyanın
dizinini (XML meta verilerinde belirtildiği şekliyle) ve
uzantısına sahip olur. FileProvider
, dizinleri yola nasıl eşler?
XML meta verilerine dayalı segmentler başlıklı bölümde açıklanmıştır
Paylaşılabilir dizinleri belirtin.
Aşağıdaki snippet, seçilen dosyanın nasıl algılanacağını ve dosya için içerik URI'sinin nasıl alınacağını gösterir:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> /* * Get a File for the selected file name. * Assume that the file names are in the * imageFilename array. */ val requestFile = File(imageFilenames[position]) /* * Most file-related method calls need to be in * try-catch blocks. */ // Use the FileProvider to get a content URI val fileUri: Uri? = try { FileProvider.getUriForFile( this@MainActivity, "com.example.myapp.fileprovider", requestFile) } catch (e: IllegalArgumentException) { Log.e("File Selector", "The selected file can't be shared: $requestFile") null } ... } ... }
Java
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override /* * When a filename in the ListView is clicked, get its * content URI and send it to the requesting app */ public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { /* * Get a File for the selected file name. * Assume that the file names are in the * imageFilename array. */ File requestFile = new File(imageFilename[position]); /* * Most file-related method calls need to be in * try-catch blocks. */ // Use the FileProvider to get a content URI try { fileUri = FileProvider.getUriForFile( MainActivity.this, "com.example.myapp.fileprovider", requestFile); } catch (IllegalArgumentException e) { Log.e("File Selector", "The selected file can't be shared: " + requestFile.toString()); } ... } }); ... }
Yalnızca dizinde bulunan dosyalar için içerik URI'leri oluşturabileceğinizi unutmayın.
<paths>
öğesini içeren meta veri dosyasında belirttiğiniz
Paylaşılabilir dizinleri belirtme bölümünde açıklanmıştır. Arama yaptığınızda
Şunun için getUriForFile()
:
File
belirtirken belirtmediğiniz bir yolda
IllegalArgumentException
.
Dosya için gerekli izinleri verme
Artık başka bir uygulamayla paylaşmak istediğiniz dosyanın İçerik URI'sına sahip olduğunuza göre
istemci uygulamasının dosyaya erişmesine izin vermelidir. Erişime izin vermek için aşağıdaki adımları uygulayarak istemci uygulamasına izin verin:
içerik URI'sini bir Intent
öğesine eklemek ve ardından
Intent
. Verdiğiniz izinler geçicidir ve süresi dolar.
ve alıcı uygulamanın görev yığını tamamlandığında otomatik olarak oluşturulur.
Aşağıdaki kod snippet'i, dosya için okuma izninin nasıl ayarlanacağını gösterir:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> ... if (fileUri != null) { // Grant temporary read permission to the content URI resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) ... } ... } ... }
Java
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks in the ListView fileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { ... if (fileUri != null) { // Grant temporary read permission to the content URI resultIntent.addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION); } ... } ... }); ... }
Dikkat: Tek yapmanız gereken setFlags()
numaralı telefonu aramak
Bu da, geçici erişim izinlerini kullanarak dosyalarınıza güvenli bir şekilde erişim izni vermenin bir yoludur. Telefon etmekten kaçının
Context.grantUriPermission()
yöntem için
dosyanın içerik URI'sini kullanın, çünkü bu yöntem yalnızca
Context.revokeUriPermission()
aranıyor.
Uri.fromFile()
kullanmayın. Uygulamaları almayı zorunlu kılar
READ_EXTERNAL_STORAGE
iznini almak için
kullanıcılar arasında ve farklı sürümlerde hiç çalışmayacaktır
Android 4.4'ten (API düzeyi 19) düşük bir sürüme sahip olmak için
uygulamanın WRITE_EXTERNAL_STORAGE
olmasını sağlayın.
Gmail uygulaması gibi gerçekten önemli paylaşım hedeflerinde,
READ_EXTERNAL_STORAGE
nedeniyle
çağrının başarısız olmasına neden olabilir.
Bunun yerine, diğer uygulamaların belirli URI'lere erişmesine izin vermek için URI izinlerini kullanabilirsiniz.
URI izinleri,
Uri.fromFile()
, öyle
İçerik Sağlayıcılarla ilişkili Uris'te çalışma. Sırf bu amaçla kendi uygulamanızı uygulamak yerine,
FileProvider
kullanabilirsiniz ve kullanmanız gerekir
Dosya paylaşımı bölümünde açıklandığı gibi.
Dosyayı, istekte bulunan uygulamayla paylaşın
Dosyayı isteyen uygulamayla paylaşmak için Intent
hem de içerik URI'sini ve setResult()
izinlerini içerir. Tanımladığınız Activity
tamamlandığında,
sistem, içerik URI'sini içeren Intent
öğesini istemci uygulamasına gönderir.
Aşağıdaki kod snippet'inde bunu nasıl yapacağınız gösterilmektedir:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> ... if (fileUri != null) { ... // Put the Uri and MIME type in the result Intent resultIntent.setDataAndType(fileUri, contentResolver.getType(fileUri)) // Set the result setResult(Activity.RESULT_OK, resultIntent) } else { resultIntent.setDataAndType(null, "") setResult(RESULT_CANCELED, resultIntent) } } }
Java
protected void onCreate(Bundle savedInstanceState) { ... // Define a listener that responds to clicks on a file in the ListView fileListView.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long rowId) { ... if (fileUri != null) { ... // Put the Uri and MIME type in the result Intent resultIntent.setDataAndType( fileUri, getContentResolver().getType(fileUri)); // Set the result MainActivity.this.setResult(Activity.RESULT_OK, resultIntent); } else { resultIntent.setDataAndType(null, ""); MainActivity.this.setResult(RESULT_CANCELED, resultIntent); } } });
Kullanıcılara, dosya seçtiklerinde istemci uygulamasına hemen geri dönebilecekleri bir yol sunun.
Bunu yapmanın bir yolu, onay işareti veya Bitti düğmesi sağlamaktır. Şununla bir yöntem ilişkilendir:
düğmenin
android:onClick
özelliği için de kullanılmaktadır. Yöntemde
finish()
Örnek:
Kotlin
fun onDoneClick(v: View) { // Associate a method with the Done button finish() }
Java
public void onDoneClick(View v) { // Associate a method with the Done button finish(); }
Daha fazla ilgili bilgi için aşağıdaki kaynakları inceleyebilirsiniz: