फ़ाइल शेयर करना

कॉन्टेंट यूआरआई का इस्तेमाल करके फ़ाइलें शेयर करने के लिए, अपने ऐप्लिकेशन को सेट अप कर लेने के बाद, आपके पास अन्य ऐप्लिकेशन के अनुरोध नहीं कर सकते. इन अनुरोधों का जवाब देने का एक तरीका यह है कि आप कोई फ़ाइल चुनें जिसे दूसरे ऐप्लिकेशन शुरू कर सकते हैं. इस तरीके से, क्लाइंट को एक ऐसा ऐप्लिकेशन है जिससे उपयोगकर्ता सर्वर ऐप्लिकेशन से फ़ाइल चुन सकते हैं और चुनी गई फ़ाइल को पा सकते हैं कॉन्टेंट यूआरआई.

इस लेसन में, अपने ऐप्लिकेशन में फ़ाइल चुनने के विकल्प Activity को बनाने का तरीका बताया गया है जो फ़ाइलों के अनुरोधों का जवाब देती है.

फ़ाइल के अनुरोध पाना

क्लाइंट ऐप्लिकेशन से फ़ाइलों के अनुरोध पाने और कॉन्टेंट यूआरआई के साथ जवाब देने के लिए, आपके ऐप्लिकेशन को Activity फ़ाइल चुनने के लिए विकल्प दें. क्लाइंट ऐप्लिकेशन इसे शुरू करते हैं कार्रवाई के लिए Intent के साथ startActivityForResult() को कॉल करके Activity ACTION_PICK. जब क्लाइंट ऐप्लिकेशन कॉल करता है startActivityForResult(), आपका ऐप्लिकेशन ये काम कर सकता है उपयोगकर्ता की चुनी गई फ़ाइल के लिए, कॉन्टेंट यूआरआई के तौर पर क्लाइंट ऐप्लिकेशन में नतीजे के तौर पर.

क्लाइंट ऐप्लिकेशन में, फ़ाइल के लिए अनुरोध लागू करने का तरीका जानने के लिए, लेसन देखें शेयर की गई फ़ाइल का अनुरोध करना.

फ़ाइल चुनने की गतिविधि बनाएं

Activity फ़ाइल चुनने का विकल्प सेट अप करने के लिए, आपके मेनिफ़ेस्ट में मौजूद Activity इंटेंट फ़िल्टर के साथ जो ACTION_PICK कार्रवाई से मेल खाता है और कैटगरी CATEGORY_DEFAULT और CATEGORY_OPENABLE. MIME टाइप फ़िल्टर भी जोड़ें उन फ़ाइलों के लिए जिन्हें आपका ऐप्लिकेशन अन्य ऐप्लिकेशन पर उपलब्ध कराता है. नीचे दिया गया स्निपेट आपको नया Activity और इंटेंट फ़िल्टर:

<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>

कोड में फ़ाइल चुनने की गतिविधि तय करें

इसके बाद, एक Activity सब-क्लास तय करें, जो यहां से उपलब्ध फ़ाइलें दिखाती है डिवाइस के स्टोरेज में मौजूद आपके ऐप्लिकेशन की files/images/ डायरेक्ट्री और उपयोगकर्ता को पसंदीदा फ़ाइल चुनें. नीचे दिया गया स्निपेट इसे Activity और उपयोगकर्ता के चुने गए विकल्पों पर जवाब दें:

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
         */
         ...
    }
    ...
}

चुनी गई फ़ाइल का जवाब दें

जब कोई उपयोगकर्ता किसी शेयर की गई फ़ाइल को चुनता है, तो आपके ऐप्लिकेशन को यह तय करना होता है कि कौनसी फ़ाइल चुनी गई है और तो उस फ़ाइल के लिए कॉन्टेंट यूआरआई जनरेट करें. क्योंकि Activity जब उपयोगकर्ता किसी फ़ाइल के नाम पर क्लिक करता है, तो ListView में उपलब्ध फ़ाइलों की सूची सिस्टम onItemClick() मेथड को कॉल करता है, जिसमें आपको चुनी गई फ़ाइल मिल सकती है.

फ़ाइल के यूआरआई को एक ऐप्लिकेशन से दूसरे ऐप्लिकेशन पर भेजने के इंटेंट का इस्तेमाल करते समय, आपको ऐसा यूआरआई पाने के लिए सावधान रहना होगा, जो भी पढ़ा जा सकता है. Android 6.0 (एपीआई लेवल 23) और इसके बाद के वर्शन वाले डिवाइसों पर ऐसा किया जा सकता है विशेष आवश्यक क्योंकि Android के उस वर्शन के अनुमति मॉडल में बदलाव हुए हैं, ख़ास तौर पर READ_EXTERNAL_STORAGE की बनना अनुमति दे सकते हैं, जो शायद पाने वाले ऐप्लिकेशन में मौजूद नहीं है.

इन बातों को ध्यान में रखते हुए, हमारा सुझाव है कि आप Uri.fromFile(), जो कई कमियां हैं. यह तरीका:

  • अलग-अलग प्रोफ़ाइलों के बीच फ़ाइल शेयर करने की अनुमति नहीं है.
  • ये ज़रूरी हैं कि आपके ऐप्लिकेशन में ये चीज़ें हों WRITE_EXTERNAL_STORAGE अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है Android 4.4 (एपीआई लेवल 19) या इससे पहले के वर्शन वाले डिवाइसों पर अनुमति.
  • पाने वाले ऐप्लिकेशन में यह ज़रूरी है READ_EXTERNAL_STORAGE अनुमति, जिसमें Gmail जैसे ज़रूरी शेयर टारगेट पर कार्रवाई नहीं कर पाएंगे जिनके पास ऐसा करने की अनुमति नहीं है.

Uri.fromFile() का इस्तेमाल करने के बजाय, अन्य ऐप्लिकेशन को अनुमति देने के लिए, यूआरआई की अनुमतियों का इस्तेमाल किया जा सकता है विशिष्ट यूआरआई का उपयोग करना ज़रूरी है. यूआरआई की अनुमतियां, file:// यूआरआई पर काम नहीं करतीं Uri.fromFile() ने जनरेट किया है, लेकिन वे और कॉन्टेंट उपलब्ध कराने वालों से जुड़े यूआरआई पर काम करता है. कॉन्टेंट बनाने FileProvider एपीआई ये काम कर सकता है ऐसे यूआरआई बनाने में आपकी मदद करता है. यह तरीका उन फ़ाइलों के साथ भी काम करता है जो बाहरी स्टोरेज में, लेकिन इंटेंट भेजने वाले ऐप्लिकेशन के लोकल स्टोरेज में.

onItemClick() में, चुनी गई फ़ाइल के फ़ाइल नाम के लिए File ऑब्जेक्ट और उसे तर्क के तौर पर getUriForFile() के साथ-साथ आपके अधिकारों के उल्लंघन की वजह से, FileProvider के लिए <provider> एलिमेंट. नतीजे के तौर पर मिलने वाले कॉन्टेंट यूआरआई में अथॉरिटी, फ़ाइल के यूआरएल से जुड़ा पाथ सेगमेंट होता है डायरेक्ट्री (जैसा कि एक्सएमएल मेटा-डेटा में बताया गया है) और फ़ाइल का नाम, जिसमें एक्सटेंशन चुनें. FileProvider, डायरेक्ट्री को पाथ पर कैसे मैप करता है एक्सएमएल मेटा-डेटा पर आधारित सेगमेंट के बारे में इस सेक्शन में बताया गया है शेयर की जा सकने वाली डायरेक्ट्री तय करना.

नीचे दिया गया स्निपेट आपको चुनी गई फ़ाइल का पता लगाने और उसके लिए कॉन्टेंट यूआरआई पाने का तरीका बताता है:

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());
                }
                ...
            }
        });
        ...
    }

याद रखें कि आप सिर्फ़ उन फ़ाइलों के लिए कॉन्टेंट यूआरआई जनरेट कर सकते हैं जो किसी डायरेक्ट्री में मौजूद होती हैं आपने मेटा-डेटा फ़ाइल में बताया है जिसमें <paths> एलिमेंट शामिल है, जैसे कि शेयर की जा सकने वाली डायरेक्ट्री बताना सेक्शन में बताया गया है. अगर आपको कॉल करना है getUriForFile() किसी ऐसे पाथ में File इस्तेमाल करते हैं जिसे आपने तय नहीं किया है. ऐसा करने पर आपको IllegalArgumentException.

इस फ़ाइल के लिए अनुमतियां दें

अब आपके पास उस फ़ाइल का कॉन्टेंट यूआरआई है जिसे आपको किसी दूसरे ऐप्लिकेशन के साथ शेयर करना है, तो आपको क्लाइंट ऐप्लिकेशन को फ़ाइल ऐक्सेस करने की अनुमति दें. ऐक्सेस देने के लिए, क्लाइंट ऐप्लिकेशन को इसके मुताबिक अनुमतियां दें कॉन्टेंट यूआरआई को Intent में जोड़ना और फिर अनुमतियों के फ़्लैग को चालू करना Intent. आपने जो अनुमतियां दी हैं वे कुछ समय के लिए होती हैं और उनकी समयसीमा खत्म हो जाती है मिलने वाले ऐप्लिकेशन का टास्क स्टैक पूरा हो जाने पर, अपने-आप अपडेट हो जाएगा.

नीचे दिया गया कोड स्निपेट आपको फ़ाइल के लिए पढ़ने की अनुमति सेट करने का तरीका बताता है:

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);
                }
                ...
             }
             ...
        });
    ...
    }

चेतावनी: सिर्फ़ setFlags() को कॉल किया जा सकता है कुछ समय के लिए ऐक्सेस की अनुमतियों का इस्तेमाल करके, आपकी फ़ाइलों को सुरक्षित तौर पर ऐक्सेस करने का तरीका बताया गया है. कॉल करने से बचें Context.grantUriPermission() तरीका फ़ाइल का सामग्री यूआरआई है, क्योंकि यह विधि ऐसी पहुंच देती है जिसे आप केवल Context.revokeUriPermission() को कॉल किया जा रहा है.

Uri.fromFile() का इस्तेमाल न करें. ऐसा करने पर ऐप्लिकेशन READ_EXTERNAL_STORAGE की अनुमति पाने के लिए, यदि आप उपयोगकर्ताओं के बीच या वर्शन में साझा करने का प्रयास कर रहे हैं तो यह बिलकुल भी काम नहीं करेगा का वर्शन 4.4 (एपीआई लेवल 19) से कम का है, तो WRITE_EXTERNAL_STORAGE वाला ऐप्लिकेशन होना चाहिए. और Gmail ऐप्लिकेशन जैसे महत्वपूर्ण साझाकरण लक्ष्यों के पास READ_EXTERNAL_STORAGE की वजह से इस कॉल को पूरा नहीं कर पाएंगे. इसके बजाय, दूसरे ऐप्लिकेशन को खास यूआरआई का ऐक्सेस देने के लिए, यूआरआई की अनुमतियों का इस्तेमाल किया जा सकता है. हालांकि, यूआरआई की अनुमतियां file:// यूआरआई पर काम नहीं करतीं, जैसा कि इन्हें जनरेट किया जाता है Uri.fromFile(), उन्हें लगता है जो कॉन्टेंट देने वालों के साथ जुड़ी Uris पर काम करते हैं. सिर्फ़ इसके लिए अपने बजट का इस्तेमाल करने के बजाय, FileProvider का इस्तेमाल किया जा सकता है और ऐसा करना चाहिए जैसा कि फ़ाइल शेयर करना में बताया गया है.

अनुरोध करने वाले ऐप्लिकेशन के साथ फ़ाइल शेयर करें

अनुरोध करने वाले ऐप्लिकेशन के साथ फ़ाइल शेयर करने के लिए, Intent को पास करें कॉन्टेंट यूआरआई और setResult() की अनुमतियां शामिल हैं. आपने अभी-अभी जो Activity तय किया है वह पूरा हो जाने पर, सिस्टम, कॉन्टेंट यूआरआई वाले Intent को क्लाइंट ऐप्लिकेशन को भेजता है. नीचे दिया गया कोड स्निपेट आपको इसका तरीका बताता है:

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);
                    }
                }
        });

उपयोगकर्ताओं को ऐसा तरीका उपलब्ध कराएं जिससे वे फ़ाइल चुनने के बाद, क्लाइंट ऐप्लिकेशन पर तुरंत वापस जा सकें. ऐसा करने का एक तरीका यह है कि आप सही का निशान या हो गया बटन उपलब्ध कराएं. किसी तरीके को इसके साथ जोड़ें बटन का इस्तेमाल करके android:onClick एट्रिब्यूट की वैल्यू सबमिट करें. तरीके में, finish(). उदाहरण के लिए:

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();
    }

इससे जुड़ी अतिरिक्त जानकारी के लिए, इन्हें देखें: