একটি ফাইল শেয়ার করা হচ্ছে

একবার আপনি কন্টেন্ট URI ব্যবহার করে ফাইল শেয়ার করার জন্য আপনার অ্যাপ সেট আপ করলে, আপনি সেই ফাইলগুলির জন্য অন্যান্য অ্যাপের অনুরোধে সাড়া দিতে পারেন। এই অনুরোধগুলিতে সাড়া দেওয়ার একটি উপায় হল সার্ভার অ্যাপ থেকে একটি ফাইল নির্বাচন ইন্টারফেস প্রদান করা যা অন্য অ্যাপ্লিকেশনগুলিকে আহ্বান করতে পারে। এই পদ্ধতিটি একটি ক্লায়েন্ট অ্যাপ্লিকেশনকে ব্যবহারকারীদের সার্ভার অ্যাপ থেকে একটি ফাইল নির্বাচন করতে দেয় এবং তারপরে নির্বাচিত ফাইলের বিষয়বস্তু URI পেতে দেয়।

এই পাঠটি আপনাকে দেখায় কিভাবে আপনার অ্যাপে একটি ফাইল নির্বাচন Activity তৈরি করতে হয় যা ফাইলের অনুরোধে সাড়া দেয়।

ফাইল অনুরোধ গ্রহণ

ক্লায়েন্ট অ্যাপ্লিকেশানগুলি থেকে ফাইলগুলির জন্য অনুরোধগুলি পেতে এবং একটি বিষয়বস্তু URI দিয়ে প্রতিক্রিয়া জানাতে, আপনার অ্যাপটিকে একটি ফাইল নির্বাচন Activity প্রদান করা উচিত। ক্লায়েন্ট অ্যাপ্লিকেশানগুলি ACTION_PICK অ্যাকশন ধারণকারী একটি Intent সহ startActivityForResult() কল করে এই Activity শুরু করে। যখন ক্লায়েন্ট অ্যাপ startActivityForResult() কল করে, আপনার অ্যাপ ব্যবহারকারীর নির্বাচিত ফাইলের জন্য একটি বিষয়বস্তু URI আকারে ক্লায়েন্ট অ্যাপে একটি ফলাফল ফেরত দিতে পারে।

একটি ক্লায়েন্ট অ্যাপে একটি ফাইলের জন্য একটি অনুরোধ কীভাবে বাস্তবায়ন করতে হয় তা শিখতে, একটি ভাগ করা ফাইলের অনুরোধ করার পাঠটি দেখুন।

একটি ফাইল নির্বাচন কার্যকলাপ তৈরি করুন

ফাইল নির্বাচন 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 সংজ্ঞায়িত করতে হয় এবং ব্যবহারকারীর নির্বাচনের প্রতিক্রিয়া জানাতে হয়:

কোটলিন

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

জাভা

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

একটি ফাইল নির্বাচন প্রতিক্রিয়া

একবার একজন ব্যবহারকারী একটি ভাগ করা ফাইল নির্বাচন করলে, আপনার অ্যাপ্লিকেশনটিকে অবশ্যই নির্ধারণ করতে হবে কোন ফাইলটি নির্বাচন করা হয়েছে এবং তারপর ফাইলটির জন্য একটি সামগ্রী URI তৈরি করতে হবে৷ যেহেতু Activity একটি ListView এ উপলব্ধ ফাইলগুলির তালিকা প্রদর্শন করে, যখন ব্যবহারকারী একটি ফাইলের নাম ক্লিক করে সিস্টেমটি কল করে onItemClick() পদ্ধতিটি, যেখানে আপনি নির্বাচিত ফাইলটি পেতে পারেন।

একটি ফাইলের ইউআরআই এক অ্যাপ থেকে অন্য অ্যাপে পাঠানোর উদ্দেশ্য ব্যবহার করার সময়, অন্য অ্যাপ পড়তে পারে এমন একটি URI পেতে আপনাকে অবশ্যই সতর্ক থাকতে হবে। Android 6.0 (API লেভেল 23) এবং পরে চলমান ডিভাইসগুলিতে এটি করার জন্য বিশেষ যত্নের প্রয়োজন কারণ Android-এর সেই সংস্করণে অনুমতি মডেলের পরিবর্তন, বিশেষ করে READ_EXTERNAL_STORAGE এর একটি বিপজ্জনক অনুমতি হয়ে উঠছে, যা গ্রহণকারী অ্যাপের অভাব হতে পারে৷

এই বিবেচনাগুলি মাথায় রেখে, আমরা সুপারিশ করি যে আপনি Uri.fromFile() ব্যবহার করা এড়িয়ে চলুন, যা বেশ কয়েকটি ত্রুটি উপস্থাপন করে। এই পদ্ধতি:

  • প্রোফাইল জুড়ে ফাইল শেয়ার করার অনুমতি দেয় না।
  • Android 4.4 (API স্তর 19) বা তার নিচের সংস্করণে চলমান ডিভাইসগুলিতে আপনার অ্যাপের WRITE_EXTERNAL_STORAGE অনুমতি থাকা প্রয়োজন৷
  • প্রাপ্ত অ্যাপগুলির READ_EXTERNAL_STORAGE অনুমতি থাকা প্রয়োজন, যা গুরুত্বপূর্ণ শেয়ার লক্ষ্যে ব্যর্থ হবে, যেমন Gmail, যেগুলির কাছে সেই অনুমতি নেই৷

Uri.fromFile() ব্যবহার করার পরিবর্তে, আপনি নির্দিষ্ট URI-তে অন্যান্য অ্যাপকে অ্যাক্সেস দেওয়ার জন্য URI অনুমতি ব্যবহার করতে পারেন। URI অনুমতি Uri.fromFile() দ্বারা উত্পন্ন file:// URI-তে কাজ না করলেও, তারা বিষয়বস্তু প্রদানকারীদের সাথে যুক্ত URI-তে কাজ করে। FileProvider API আপনাকে এই ধরনের URI তৈরি করতে সাহায্য করতে পারে। এই পদ্ধতিটি এমন ফাইলগুলির সাথেও কাজ করে যেগুলি বাহ্যিক স্টোরেজে নয়, কিন্তু অভিপ্রায় পাঠানোর অ্যাপের স্থানীয় সঞ্চয়স্থানে।

onItemClick() এ, নির্বাচিত ফাইলের ফাইলের নামের জন্য একটি File অবজেক্ট পান এবং এটিকে একটি আর্গুমেন্ট হিসাবে getUriForFile() এ পাস করুন, সেই অথরিটির সাথে যা আপনি FileProvider এর জন্য <provider> উপাদানে নির্দিষ্ট করেছেন। ফলস্বরূপ কন্টেন্ট ইউআরআই-এ কর্তৃপক্ষ, ফাইলের ডিরেক্টরির সাথে সম্পর্কিত একটি পাথ সেগমেন্ট (এক্সএমএল মেটা-ডেটাতে উল্লেখ করা হয়েছে) এবং ফাইলের নাম এর এক্সটেনশন সহ রয়েছে। কিভাবে FileProvider এক্সএমএল মেটা-ডেটার উপর ভিত্তি করে ডাইরেক্টরিগুলিকে পাথ সেগমেন্টে ম্যাপ করে সে অংশে বর্ণনা করা হয়েছে শেয়ারযোগ্য ডিরেক্টরি নির্দিষ্ট করুন

নিম্নলিখিত স্নিপেট আপনাকে দেখায় কিভাবে নির্বাচিত ফাইলটি সনাক্ত করতে হয় এবং এটির জন্য একটি সামগ্রী URI পেতে হয়:

কোটলিন

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

জাভা

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

মনে রাখবেন যে আপনি শুধুমাত্র সেই ফাইলগুলির জন্য সামগ্রী URI তৈরি করতে পারেন যা আপনার নির্দিষ্ট করা একটি মেটা-ডেটা ফাইলে থাকে যেখানে <paths> উপাদান রয়েছে, যেমন ভাগ করা যায় এমন ডিরেক্টরি উল্লেখ করুন। যদি আপনি একটি File জন্য getUriForFile() কল করেন যেটি আপনি নির্দিষ্ট করেননি, তাহলে আপনি একটি IllegalArgumentException পাবেন।

ফাইলের জন্য অনুমতি দিন

আপনি যে ফাইলটি অন্য অ্যাপের সাথে শেয়ার করতে চান তার জন্য এখন আপনার কাছে একটি কন্টেন্ট URI আছে, আপনাকে ক্লায়েন্ট অ্যাপটিকে ফাইলটি অ্যাক্সেস করার অনুমতি দিতে হবে। অ্যাক্সেসের অনুমতি দিতে, একটি Intent সামগ্রী URI যোগ করে এবং তারপরে Intent অনুমতি ফ্ল্যাগ সেট করে ক্লায়েন্ট অ্যাপকে অনুমতি দিন। আপনি যে অনুমতিগুলি প্রদান করেন তা অস্থায়ী এবং স্বয়ংক্রিয়ভাবে মেয়াদ শেষ হয়ে যায় যখন গ্রহনকারী অ্যাপের টাস্ক স্ট্যাক শেষ হয়।

নিম্নলিখিত কোড স্নিপেট আপনাকে দেখায় কিভাবে ফাইলের জন্য পড়ার অনুমতি সেট করতে হয়:

কোটলিন

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

জাভা

    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() কল করা। একটি ফাইলের বিষয়বস্তুর URI-এর জন্য Context.grantUriPermission() পদ্ধতিতে কল করা এড়িয়ে চলুন, যেহেতু এই পদ্ধতিটি অ্যাক্সেস মঞ্জুর করে যা আপনি শুধুমাত্র Context.revokeUriPermission() কল করে প্রত্যাহার করতে পারেন।

Uri.fromFile() ব্যবহার করবেন না। এটি গ্রহনকারী অ্যাপগুলিকে READ_EXTERNAL_STORAGE অনুমতি নিতে বাধ্য করে, আপনি যদি ব্যবহারকারীদের মধ্যে শেয়ার করার চেষ্টা করছেন এবং Android এর 4.4 (API স্তর 19) এর চেয়ে কম সংস্করণে, তাহলে আপনার অ্যাপের WRITE_EXTERNAL_STORAGE থাকা প্রয়োজন হলে তা মোটেও কাজ করবে না। এবং সত্যিই গুরুত্বপূর্ণ শেয়ার টার্গেট, যেমন Gmail অ্যাপে READ_EXTERNAL_STORAGE নেই, যার ফলে এই কলটি ব্যর্থ হয়েছে৷ পরিবর্তে, আপনি নির্দিষ্ট URI-তে অন্যান্য অ্যাপকে অ্যাক্সেস দেওয়ার জন্য URI অনুমতি ব্যবহার করতে পারেন। URI অনুমতিগুলি Uri.fromFile() দ্বারা তৈরি করা ফাইল:// URI-তে কাজ না করলেও, তারা বিষয়বস্তু প্রদানকারীদের সাথে যুক্ত Uris-এ কাজ করে। শুধুমাত্র এই জন্য আপনার নিজের বাস্তবায়ন করার পরিবর্তে, আপনি ফাইল শেয়ারিং -এ ব্যাখ্যা করা হিসাবে FileProvider ব্যবহার করতে পারেন এবং করা উচিত।

অনুরোধকারী অ্যাপের সাথে ফাইলটি শেয়ার করুন

যে অ্যাপটি অনুরোধ করেছে তার সাথে ফাইলটি শেয়ার করতে, কন্টেন্ট ইউআরআই সহ Intent পাস করুন এবং setResult() এ অনুমতি দিন। যখন আপনি এইমাত্র সংজ্ঞায়িত Activity শেষ করেছেন, তখন সিস্টেমটি ক্লায়েন্ট অ্যাপে বিষয়বস্তু URI সহ Intent পাঠায়। নিম্নলিখিত কোড স্নিপেট আপনাকে দেখায় কিভাবে এটি করতে হয়:

কোটলিন

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

জাভা

    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() । উদাহরণ স্বরূপ:

কোটলিন

    fun onDoneClick(v: View) {
        // Associate a method with the Done button
        finish()
    }

জাভা

    public void onDoneClick(View v) {
        // Associate a method with the Done button
        finish();
    }

অতিরিক্ত সম্পর্কিত তথ্যের জন্য, পড়ুন: