APK विस्‍तार फ़ाइलें

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

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

अगर आपको एक्सपैंशन फ़ाइलों का इस्तेमाल नहीं करना है और आपके ऐप्लिकेशन का कंप्रेस किया गया डाउनलोड साइज़ 100 एमबी से ज़्यादा है, तो आपको Android ऐप्लिकेशन बंडल का इस्तेमाल करके अपना ऐप्लिकेशन अपलोड करना चाहिए. इससे, कंप्रेस किए गए ऐप्लिकेशन का डाउनलोड साइज़ 200 एमबी तक हो सकता है. इसके अलावा, ऐप्लिकेशन बंडल का इस्तेमाल करने पर, Google Play पर APK जनरेट करने और साइन करने की प्रोसेस में देरी होती है. इसलिए, उपयोगकर्ता सिर्फ़ उस कोड और संसाधनों के साथ ऑप्टिमाइज़ किए गए APK डाउनलोड करते हैं जो आपके ऐप्लिकेशन को चलाने के लिए ज़रूरी होते हैं. आपको एक से ज़्यादा APK या एक्सपैंशन फ़ाइलें बनाने, साइन करने, और मैनेज करने की ज़रूरत नहीं होती. साथ ही, उपयोगकर्ताओं को छोटे और ज़्यादा ऑप्टिमाइज़ किए गए APK डाउनलोड करने को मिलते हैं.

खास जानकारी

Google Play Console का इस्तेमाल करके हर बार APK अपलोड करने पर, आपके पास APK में एक या दो एक्सपैंशन फ़ाइलें जोड़ने का विकल्प होता है. हर फ़ाइल का साइज़ ज़्यादा से ज़्यादा दो जीबी हो सकता है. साथ ही, यह किसी भी फ़ॉर्मैट में हो सकती है. हालांकि, हमारा सुझाव है कि डाउनलोड के दौरान बैंडविड्थ बचाने के लिए, आप संपीड़ित फ़ाइल का इस्तेमाल करें. कॉन्सेप्ट के हिसाब से, हर एक्सपैंशन फ़ाइल की भूमिका अलग होती है:

  • मुख्य एक्सपैंशन फ़ाइल, आपके ऐप्लिकेशन के लिए ज़रूरी अतिरिक्त संसाधनों की मुख्य एक्सपैंशन फ़ाइल होती है.
  • पैच एक्सपैंशन फ़ाइल को सबमिट करना ज़रूरी नहीं है. इसका मकसद, मुख्य एक्सपैंशन फ़ाइल में छोटे अपडेट करना है.

दोनों एक्सपैंशन फ़ाइलों का इस्तेमाल अपनी पसंद के मुताबिक किया जा सकता है. हालांकि, हमारा सुझाव है कि मुख्य एक्सपैंशन फ़ाइल में मुख्य एसेट डिलीवर की जाएं और उसे कभी-कभी ही अपडेट किया जाए. पैच एक्सपैंशन फ़ाइल छोटी होनी चाहिए और "पैच कैरियर" के तौर पर काम करनी चाहिए. इसे हर बड़ी रिलीज़ या ज़रूरत पड़ने पर अपडेट किया जाना चाहिए.

हालांकि, अगर आपके ऐप्लिकेशन के अपडेट के लिए सिर्फ़ नई पैच एक्सपैंशन फ़ाइल की ज़रूरत है, तब भी आपको मेनिफ़ेस्ट में अपडेट किए गए versionCode के साथ नया APK अपलोड करना होगा. (Play Console, किसी मौजूदा APK में एक्सपैंशन फ़ाइल अपलोड करने की अनुमति नहीं देता.)

ध्यान दें: पैच एक्सपैंशन फ़ाइल और मुख्य एक्सपैंशन फ़ाइल, दोनों एक जैसी होती हैं. इनमें से किसी भी फ़ाइल का इस्तेमाल, अपनी पसंद के मुताबिक किया जा सकता है.

फ़ाइल के नाम का फ़ॉर्मैट

अपलोड की गई हर एक्सपैंशन फ़ाइल, आपके चुने गए किसी भी फ़ॉर्मैट (ZIP, PDF, MP4 वगैरह) में हो सकती है. JOBB टूल का इस्तेमाल करके, संसाधन फ़ाइलों के सेट और उस सेट के बाद के पैच को एन्क्रिप्ट और कवर किया जा सकता है. फ़ाइल टाइप चाहे जो भी हो, Google Play उन्हें अस्पष्ट बाइनरी ब्लॉब मानता है और इस स्कीम का इस्तेमाल करके फ़ाइलों का नाम बदल देता है:

[main|patch].<expansion-version>.<package-name>.obb

इस योजना के तीन कॉम्पोनेंट हैं:

main या patch
यह बताता है कि फ़ाइल मुख्य एक्सपैंशन फ़ाइल है या पैच एक्सपैंशन फ़ाइल. हर APK के लिए, सिर्फ़ एक मुख्य फ़ाइल और एक पैच फ़ाइल हो सकती है.
<expansion-version>
यह एक पूर्णांक है, जो उस APK के वर्शन कोड से मेल खाता है जिसके साथ एक्सपैंशन पहले से जुड़ा है. यह ऐप्लिकेशन की android:versionCode वैल्यू से मेल खाता है.

"पहली" पर ज़ोर इसलिए दिया गया है, क्योंकि Play Console पर अपलोड की गई एक्सपैंशन फ़ाइल का इस्तेमाल, नए APK के साथ फिर से किया जा सकता है. हालांकि, एक्सपैंशन फ़ाइल का नाम नहीं बदलता. यह उस वर्शन को बनाए रखती है जो पहली बार फ़ाइल अपलोड करते समय उस पर लागू किया गया था.

<package-name>
आपके ऐप्लिकेशन का Java-style पैकेज का नाम.

उदाहरण के लिए, मान लें कि आपके APK का वर्शन 314159 है और आपके पैकेज का नाम com.example.app है. अगर आपने मुख्य एक्सपैंशन फ़ाइल अपलोड की है, तो फ़ाइल का नाम बदलकर यह हो जाएगा:

main.314159.com.example.app.obb

सेव करने की जगह

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

getObbDir() तरीका, आपकी एक्सपैंशन फ़ाइलों के लिए, इस फ़ॉर्मैट में खास जगह दिखाता है:

<shared-storage>/Android/obb/<package-name>/
  • <shared-storage>, शेयर किए गए स्टोरेज स्पेस का पाथ है. यह getExternalStorageDirectory() से उपलब्ध है.
  • <package-name> आपके ऐप्लिकेशन का Java-style पैकेज नाम है, जो getPackageName() से उपलब्ध है.

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

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Android 6 और उसके बाद के वर्शन के लिए, रनटाइम के दौरान बाहरी स्टोरेज की अनुमति का अनुरोध करना ज़रूरी है. हालांकि, Android के कुछ वर्शन में OBB फ़ाइलों को पढ़ने के लिए अनुमति की ज़रूरत नहीं होती. यहां दिया गया कोड स्निपेट, बाहरी स्टोरेज की अनुमति मांगने से पहले, पढ़ने का ऐक्सेस देखने का तरीका दिखाता है:

Kotlin

val obb = File(obb_filename)
var open_failed = false

try {
    BufferedReader(FileReader(obb)).also { br ->
        ReadObbFile(br)
    }
} catch (e: IOException) {
    open_failed = true
}

if (open_failed) {
    // request READ_EXTERNAL_STORAGE permission before reading OBB file
    ReadObbFileWithPermission()
}

Java

File obb = new File(obb_filename);
 boolean open_failed = false;

 try {
     BufferedReader br = new BufferedReader(new FileReader(obb));
     open_failed = false;
     ReadObbFile(br);
 } catch (IOException e) {
     open_failed = true;
 }

 if (open_failed) {
     // request READ_EXTERNAL_STORAGE permission before reading OBB file
     ReadObbFileWithPermission();
 }

अगर आपको एक्सपैंशन फ़ाइलों के कॉन्टेंट को अनपैक करना है, तो इसके बाद OBB एक्सपैंशन फ़ाइलों को मिटाएं. साथ ही, अनपैक किए गए डेटा को उसी डायरेक्ट्री में सेव करें. आपको अपनी अनपैक की गई फ़ाइलों को getExternalFilesDir() से तय की गई डायरेक्ट्री में सेव करना चाहिए. हालांकि, अगर हो सके, तो एक्सपैंशन फ़ाइल फ़ॉर्मैट का इस्तेमाल करें. इससे, डेटा को अनपैक करने के बजाय, सीधे फ़ाइल से पढ़ा जा सकता है. उदाहरण के लिए, हमने APK एक्सपैंशन ZIP लाइब्रेरी नाम का एक लाइब्रेरी प्रोजेक्ट उपलब्ध कराया है. यह सीधे ZIP फ़ाइल से आपका डेटा पढ़ता है.

चेतावनी: APK फ़ाइलों के उलट, शेयर किए गए स्टोरेज में सेव की गई किसी भी फ़ाइल को उपयोगकर्ता और अन्य ऐप्लिकेशन पढ़ सकते हैं.

सलाह: अगर मीडिया फ़ाइलों को ZIP फ़ाइल में पैकेज किया जा रहा है, तो ऑफ़सेट और लंबाई कंट्रोल (जैसे कि MediaPlayer.setDataSource() और SoundPool.load()) की मदद से, फ़ाइलों पर मीडिया चलाने के कॉल का इस्तेमाल किया जा सकता है. इसके लिए, आपको ZIP फ़ाइल को अनपैक करने की ज़रूरत नहीं है. इसके काम करने के लिए, ज़िप पैकेज बनाते समय आपको मीडिया फ़ाइलों को फिर से कंप्रेस नहीं करना चाहिए. उदाहरण के लिए, zip टूल का इस्तेमाल करते समय, आपको उन फ़ाइल के सफ़िक्स तय करने के लिए -n विकल्प का इस्तेमाल करना चाहिए जिन्हें कंप्रेस नहीं करना है:
zip -n .mp4;.ogg main_expansion media_files

डाउनलोड करने की प्रोसेस

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

बड़े लेवल पर, डाउनलोड करने की प्रोसेस इस तरह दिखती है:

  1. उपयोगकर्ता, Google Play से आपका ऐप्लिकेशन इंस्टॉल करने का विकल्प चुनता है.
  2. अगर Google Play, एक्सपैंशन फ़ाइलें डाउनलोड कर पाता है (ज़्यादातर डिवाइसों के लिए ऐसा होता है), तो वह उन्हें APK के साथ डाउनलोड कर देता है.

    अगर Google Play, एक्सपैंशन फ़ाइलें डाउनलोड नहीं कर पाता है, तो वह सिर्फ़ APK डाउनलोड करता है.

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

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

डेवलपमेंट से जुड़ी चेकलिस्ट

अपने ऐप्लिकेशन के साथ एक्सपैंशन फ़ाइलों का इस्तेमाल करने के लिए, आपको ये काम करने होंगे:

  1. सबसे पहले यह तय करें कि आपके ऐप्लिकेशन के कंप्रेस किए गए डाउनलोड साइज़ को 100 एमबी से ज़्यादा करना ज़रूरी है या नहीं. स्टोरेज की कमी होती है. इसलिए, आपको डाउनलोड किए गए वीडियो का साइज़ जितना हो सके उतना कम रखना चाहिए. अगर आपका ऐप्लिकेशन, अलग-अलग स्क्रीन डेंसिटी के लिए ग्राफ़िक ऐसेट के कई वर्शन उपलब्ध कराने के लिए 100 एमबी से ज़्यादा का इस्तेमाल करता है, तो इसके बजाय एक से ज़्यादा APK पब्लिश करें. हर APK में सिर्फ़ उन स्क्रीन के लिए ज़रूरी ऐसेट शामिल करें जिन्हें टारगेट किया जा रहा है. Google Play पर पब्लिश करते समय बेहतर नतीजे पाने के लिए, Android ऐप्लिकेशन बंडल अपलोड करें. इसमें आपके ऐप्लिकेशन का पूरा कोड और संसाधन शामिल होते हैं. हालांकि, Google Play पर APK जनरेट करने और उसे साइन करने की प्रोसेस को बाद में किया जाता है.
  2. यह तय करें कि आपके APK से किन ऐप्लिकेशन संसाधनों को अलग करना है और उन्हें मुख्य एक्सपैंशन फ़ाइल के तौर पर इस्तेमाल करने के लिए, किसी फ़ाइल में पैकेज करें.

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

  3. अपने ऐप्लिकेशन को इस तरह से डेवलप करें कि वह डिवाइस के शेयर किए गए स्टोरेज में मौजूद, एक्सपैंशन फ़ाइलों के रिसॉर्स का इस्तेमाल करे.

    याद रखें कि आपको एक्सपैंशन फ़ाइलों को मिटाना, किसी दूसरी जगह ले जाना या उनका नाम नहीं बदलना चाहिए.

    अगर आपके ऐप्लिकेशन के लिए किसी खास फ़ॉर्मैट की ज़रूरत नहीं है, तो हमारा सुझाव है कि आप अपनी एक्सपैंशन फ़ाइलों के लिए ZIP फ़ाइलें बनाएं. इसके बाद, APK एक्सपैंशन ज़िप लाइब्रेरी का इस्तेमाल करके उन्हें पढ़ें.

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

    हमारा सुझाव है कि डाउनलोड करने के तरीके को लागू करने के लिए, डाउनलोड करने वाले टूल की लाइब्रेरी का इस्तेमाल करें. इससे, आपको डाउनलोड करने के लिए कम कोड लिखना पड़ेगा और उपयोगकर्ता को डाउनलोड के दौरान बेहतर अनुभव मिलेगा.

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

ऐप्लिकेशन डेवलप करने के बाद, एक्सपैंशन फ़ाइलों की जांच करने के लिए गाइड का पालन करें.

नियम और सीमाएं

APK एक्सपैंशन फ़ाइलें जोड़ने की सुविधा, Play Console का इस्तेमाल करके ऐप्लिकेशन अपलोड करने पर उपलब्ध होती है. पहली बार अपना ऐप्लिकेशन अपलोड करते समय या एक्सपैंशन फ़ाइलों का इस्तेमाल करने वाले ऐप्लिकेशन को अपडेट करते समय, आपको इन नियमों और सीमाओं के बारे में पता होना चाहिए:

  1. हर एक्सपैंशन फ़ाइल का साइज़ 2 जीबी से ज़्यादा नहीं होना चाहिए.
  2. Google Play से एक्सपैंशन फ़ाइलें डाउनलोड करने के लिए, उपयोगकर्ता के पास आपका ऐप्लिकेशन होना चाहिए. अगर ऐप्लिकेशन किसी दूसरे तरीके से इंस्टॉल किया गया था, तो Google Play आपकी एक्सपैंशन फ़ाइलों के यूआरएल नहीं देगा.
  3. अपने ऐप्लिकेशन से डाउनलोड करते समय, Google Play हर फ़ाइल के लिए एक यूनीक यूआरएल उपलब्ध कराता है. यह यूआरएल हर डाउनलोड के लिए अलग होता है. साथ ही, आपके ऐप्लिकेशन को मिलने के कुछ समय बाद इसकी समयसीमा खत्म हो जाती है.
  4. अगर आपने अपने ऐप्लिकेशन को नए APK से अपडेट किया है या एक ही ऐप्लिकेशन के लिए कई APK अपलोड किए हैं, तो आपके पास उन एक्सपैंशन फ़ाइलों को चुनने का विकल्प होता है जिन्हें आपने पिछले APK के लिए अपलोड किया था. एक्सपैंशन फ़ाइल का नाम नहीं बदलता—इसमें उस APK का वर्शन बना रहता है जिससे फ़ाइल मूल रूप से जुड़ी थी.
  5. अगर अलग-अलग डिवाइसों के लिए अलग-अलग एक्सपैंशन फ़ाइलें उपलब्ध कराने के लिए, कई APKs के साथ एक्सपैंशन फ़ाइलों का इस्तेमाल किया जाता है, तो भी आपको हर डिवाइस के लिए अलग-अलग APK अपलोड करने होंगे. ऐसा इसलिए, ताकि हर डिवाइस के लिए एक यूनीक versionCode वैल्यू दी जा सके और हर APK के लिए अलग-अलग फ़िल्टर तय किए जा सकें.
  6. सिर्फ़ एक्सपैंशन फ़ाइलों में बदलाव करके, अपने ऐप्लिकेशन का अपडेट जारी नहीं किया जा सकता. अपने ऐप्लिकेशन को अपडेट करने के लिए, आपको नया APK अपलोड करना होगा. अगर आपके बदलाव सिर्फ़ एक्सपैंशन फ़ाइलों में मौजूद एसेट से जुड़े हैं, तो versionCode (और शायद versionName) को बदलकर, अपने APK को अपडेट किया जा सकता है.
  7. अपनी obb/ Directory में कोई दूसरा डेटा सेव न करें. अगर आपको कुछ डेटा अनपैक करना है, तो उसे getExternalFilesDir() की बताई गई जगह पर सेव करें.
  8. .obb एक्सपैंशन फ़ाइल को न तो मिटाएं और न ही उसका नाम बदलें. ऐसा तब तक न करें, जब तक कि आप अपडेट न कर रहे हों. ऐसा करने से, Google Play (या आपका ऐप्लिकेशन) बार-बार एक्सपैंशन फ़ाइल डाउनलोड करेगा.
  9. एक्सपैंशन फ़ाइल को मैन्युअल तरीके से अपडेट करते समय, आपको पिछली एक्सपैंशन फ़ाइल मिटानी होगी.

एक्सपैंशन फ़ाइलें डाउनलोड करना

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

एक्सपैंशन फ़ाइलें डाउनलोड करने के लिए, आपको इन बातों का ध्यान रखना होगा:

  1. जब आपका ऐप्लिकेशन शुरू हो जाए, तो शेयर की गई स्टोरेज जगह (Android/obb/<package-name>/ डायरेक्ट्री में) पर एक्सपैंशन फ़ाइलें देखें.
    1. अगर एक्सपैंशन फ़ाइलें मौजूद हैं, तो आपका ऐप्लिकेशन काम करना जारी रख सकता है.
    2. अगर एक्सपैंशन फ़ाइलें नहीं हैं, तो:
      1. अपने ऐप्लिकेशन के एक्सपैंशन फ़ाइल के नाम, साइज़, और यूआरएल पाने के लिए, Google Play की ऐप्लिकेशन लाइसेंस देने वाली सेवा का इस्तेमाल करके अनुरोध करें.
      2. एक्सपैंशन फ़ाइलें डाउनलोड करने और उन्हें सेव करने के लिए, Google Play के दिए गए यूआरएल का इस्तेमाल करें. आपको फ़ाइलों को शेयर की गई स्टोरेज जगह (Android/obb/<package-name>/) पर सेव करना ज़रूरी है. साथ ही, Google Play के रिस्पॉन्स में दिए गए फ़ाइल के नाम का इस्तेमाल करना होगा.

        ध्यान दें: Google Play, आपकी एक्सपैंशन फ़ाइलों के लिए जो यूआरएल उपलब्ध कराता है वह हर डाउनलोड के लिए अलग होता है. साथ ही, आपके ऐप्लिकेशन को यूआरएल मिलने के कुछ समय बाद उसकी समयसीमा खत्म हो जाती है.

अगर आपका ऐप्लिकेशन मुफ़्त है (पैसे चुकाकर डाउनलोड नहीं किया जाता), तो हो सकता है कि आपने ऐप्लिकेशन लाइसेंसिंग सेवा का इस्तेमाल न किया हो. इसे मुख्य रूप से, आपके ऐप्लिकेशन के लिए लाइसेंस की नीतियों को लागू करने के लिए डिज़ाइन किया गया है. साथ ही, यह पक्का करने के लिए भी डिज़ाइन किया गया है कि उपयोगकर्ता के पास आपके ऐप्लिकेशन का इस्तेमाल करने का अधिकार है. इसका मतलब है कि उसने Google Play पर इसके लिए सही तरीके से पैसे चुकाए हैं. एक्सपैंशन फ़ाइल की सुविधा को आसान बनाने के लिए, लाइसेंस देने की सेवा को बेहतर बनाया गया है. इससे आपके ऐप्लिकेशन को एक ऐसा जवाब मिलेगा जिसमें Google Play पर होस्ट की गई, आपके ऐप्लिकेशन की एक्सपैंशन फ़ाइलों का यूआरएल शामिल होगा. इसलिए, भले ही आपका ऐप्लिकेशन लोगों के लिए मुफ़्त हो, फिर भी APK एक्सपैंशन फ़ाइलों का इस्तेमाल करने के लिए, आपको लाइसेंस की पुष्टि करने वाली लाइब्रेरी (LVL) शामिल करनी होगी. अगर आपका ऐप्लिकेशन बिना किसी शुल्क के उपलब्ध है, तो आपको लाइसेंस की पुष्टि करने की ज़रूरत नहीं है. आपको सिर्फ़ लाइब्रेरी की ज़रूरत है, ताकि वह एक्सपैंशन फ़ाइलों का यूआरएल दिखाने वाला अनुरोध कर सके.

ध्यान दें: आपका ऐप्लिकेशन मुफ़्त है या नहीं, Google Play सिर्फ़ तब एक्सपैंशन फ़ाइल के यूआरएल दिखाता है, जब उपयोगकर्ता ने आपका ऐप्लिकेशन Google Play से लिया हो.

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

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

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

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

डाउनलोडर लाइब्रेरी के बारे में जानकारी

हमारा सुझाव है कि अपने ऐप्लिकेशन के साथ APK एक्सपैंशन फ़ाइलों का इस्तेमाल करें और कम से कम प्रयास करके, उपयोगकर्ताओं को बेहतर अनुभव दें. इसके लिए, Google Play APK एक्सपैंशन लाइब्रेरी पैकेज में शामिल डाउनलोडर लाइब्रेरी का इस्तेमाल करें. यह लाइब्रेरी, बैकग्राउंड सेवा में आपकी एक्सपैंशन फ़ाइलें डाउनलोड करती है. साथ ही, डाउनलोड की स्थिति के साथ उपयोगकर्ता को सूचना दिखाती है, नेटवर्क कनेक्शन के बंद होने पर उसे मैनेज करती है, और डाउनलोड की प्रोसेस को फिर से शुरू करती है.

डाउनलोडर लाइब्रेरी का इस्तेमाल करके, एक्सपैंशन फ़ाइल डाउनलोड करने की सुविधा लागू करने के लिए, आपको बस इतना करना होगा:

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

यहां दिए गए सेक्शन में, Downloader Library का इस्तेमाल करके ऐप्लिकेशन सेट अप करने का तरीका बताया गया है.

डाउनलोडर लाइब्रेरी का इस्तेमाल करने की तैयारी करना

डाउनलोडर लाइब्रेरी का इस्तेमाल करने के लिए, आपको SDK मैनेजर से दो पैकेज डाउनलोड करने होंगे और अपने ऐप्लिकेशन में सही लाइब्रेरी जोड़नी होंगी.

सबसे पहले, Android SDK Manager (टूल > SDK Manager) खोलें. इसके बाद, दिखने का तरीका और काम करने का तरीका > सिस्टम सेटिंग > Android SDK में जाकर, SDK टूल टैब चुनें. इसके बाद, इनमें से कोई एक टूल चुनें और डाउनलोड करें:

  • Google Play लाइसेंसिंग लाइब्रेरी पैकेज
  • Google Play APK एक्सपैंशन लाइब्रेरी पैकेज

लाइसेंस की पुष्टि करने वाली लाइब्रेरी और डाउनलोडर लाइब्रेरी के लिए, एक नया लाइब्रेरी मॉड्यूल बनाएं. हर लाइब्रेरी के लिए:

  1. फ़ाइल > नया > नया मॉड्यूल चुनें.
  2. नया मॉड्यूल बनाएं विंडो में, Android लाइब्रेरी को चुनें. इसके बाद, आगे बढ़ें को चुनें.
  3. ऐप्लिकेशन/लाइब्रेरी का नाम डालें, जैसे कि "Google Play लाइसेंस लाइब्रेरी" और "Google Play डाउनलोडर लाइब्रेरी". इसके बाद, SDK टूल का कम से कम लेवल चुनें और फिर पूरा करें को चुनें.
  4. फ़ाइल > प्रोजेक्ट का स्ट्रक्चर चुनें.
  5. प्रॉपर्टी टैब चुनें. इसके बाद, लाइब्रेरी रिपॉज़िटरी में जाकर, <sdk>/extras/google/ डायरेक्ट्री से लाइब्रेरी डालें. लाइसेंस की पुष्टि करने वाली लाइब्रेरी के लिए play_licensing/ और डाउनलोडर लाइब्रेरी के लिए play_apk_expansion/downloader_library/ डालें.
  6. नया मॉड्यूल बनाने के लिए, ठीक है चुनें.

ध्यान दें: डाउनलोडर लाइब्रेरी, लाइसेंस की पुष्टि करने वाली लाइब्रेरी पर निर्भर करती है. डाउनलोडर लाइब्रेरी की प्रोजेक्ट प्रॉपर्टी में, लाइसेंस की पुष्टि करने वाली लाइब्रेरी को ज़रूर जोड़ें.

इसके अलावा, कमांड लाइन से लाइब्रेरी शामिल करने के लिए, अपने प्रोजेक्ट को अपडेट करें:

  1. डायरेक्ट्री को <sdk>/tools/ डायरेक्ट्री में बदलें.
  2. अपने प्रोजेक्ट में LVL और Downloader Library, दोनों को जोड़ने के लिए, --library विकल्प के साथ android update project को लागू करें. उदाहरण के लिए:
    android update project --path ~/Android/MyApp \
    --library ~/android_sdk/extras/google/market_licensing \
    --library ~/android_sdk/extras/google/market_apk_expansion/downloader_library
    

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

सलाह: APK एक्सपैंशन पैकेज में एक सैंपल ऐप्लिकेशन शामिल होता है. इसमें, ऐप्लिकेशन में Downloader लाइब्रेरी का इस्तेमाल करने का तरीका बताया जाता है. सैंपल में, APK एक्सपैंशन पैकेज में उपलब्ध तीसरी लाइब्रेरी का इस्तेमाल किया जाता है. इसे APK एक्सपैंशन Zip लाइब्रेरी कहा जाता है. अगर आपको अपनी एक्सपैंशन फ़ाइलों के लिए ZIP फ़ाइलों का इस्तेमाल करना है, तो हमारा सुझाव है कि आप अपने ऐप्लिकेशन में APK एक्सपैंशन Zip लाइब्रेरी भी जोड़ें. ज़्यादा जानकारी के लिए, APK एक्सपैंशन Zip लाइब्रेरी का इस्तेमाल करना सेक्शन देखें.

उपयोगकर्ता की अनुमतियां बताना

एक्सपैंशन फ़ाइलें डाउनलोड करने के लिए, डाउनलोडर लाइब्रेरी को कई अनुमतियां चाहिए. आपको अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में इन अनुमतियों के बारे में बताना होगा. ये:

<manifest ...>
    <!-- Required to access Google Play Licensing -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />

    <!-- Required to download files from Google Play -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Required to keep CPU alive while downloading files
        (NOT to keep screen awake) -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <!-- Required to poll the state of the network connection
        and respond to changes -->
    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- Required to check whether Wi-Fi is enabled -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <!-- Required to read and write the expansion files on shared storage -->
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

ध्यान दें: डिफ़ॉल्ट रूप से, डाउनलोडर लाइब्रेरी के लिए एपीआई लेवल 4 की ज़रूरत होती है. हालांकि, APK एक्सपैंशन ज़िप लाइब्रेरी के लिए एपीआई लेवल 5 की ज़रूरत होती है.

डाउनलोडर सेवा लागू करना

बैकग्राउंड में डाउनलोड करने के लिए, डाउनलोडर लाइब्रेरी अपनी Service सबक्लास उपलब्ध कराती है, जिसे DownloaderService कहा जाता है. आपको इसे एक्सटेंड़ करना चाहिए. DownloaderService, आपके लिए एक्सपैंशन फ़ाइलें डाउनलोड करने के साथ-साथ ये काम भी करता है:

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

आपको बस अपने ऐप्लिकेशन में एक क्लास बनानी होगी, जो DownloaderService क्लास को एक्सटेंड करती हो. साथ ही, ऐप्लिकेशन की खास जानकारी देने के लिए, तीन तरीकों को बदलना होगा:

getPublicKey()
इससे एक स्ट्रिंग दिखनी चाहिए, जो आपके पब्लिशर खाते के लिए, Base64 में एन्कोड की गई आरएसए सार्वजनिक कुंजी हो. यह स्ट्रिंग, Play Console पर प्रोफ़ाइल पेज पर उपलब्ध होती है. लाइसेंसिंग के लिए सेट अप करना देखें.
getSALT()
यह रैंडम बाइट का कलेक्शन दिखाना चाहिए. लाइसेंस देने वाली Policy, Obfuscator बनाने के लिए इसका इस्तेमाल करती है. साल्ट से यह पक्का होता है कि आपका लाइसेंस डेटा, जिस SharedPreferences फ़ाइल में सेव किया गया है वह यूनीक होगी और उसे कोई भी ऐक्सेस नहीं कर पाएगा.
getAlarmReceiverClassName()
यह आपके ऐप्लिकेशन में BroadcastReceiver की उस क्लास का नाम दिखाना चाहिए जिसे यह सूचना मिलनी चाहिए कि डाउनलोड फिर से शुरू किया जाना चाहिए. ऐसा तब हो सकता है, जब डाउनलोड करने की सेवा अचानक बंद हो जाए.

उदाहरण के लिए, यहां DownloaderService को पूरी तरह से लागू करने का तरीका बताया गया है:

Kotlin

// You must use the public key belonging to your publisher account
const val BASE64_PUBLIC_KEY = "YourLVLKey"
// You should also modify this salt
val SALT = byteArrayOf(
        1, 42, -12, -1, 54, 98, -100, -12, 43, 2,
        -8, -4, 9, 5, -106, -107, -33, 45, -1, 84
)

class SampleDownloaderService : DownloaderService() {

    override fun getPublicKey(): String = BASE64_PUBLIC_KEY

    override fun getSALT(): ByteArray = SALT

    override fun getAlarmReceiverClassName(): String = SampleAlarmReceiver::class.java.name
}

Java

public class SampleDownloaderService extends DownloaderService {
    // You must use the public key belonging to your publisher account
    public static final String BASE64_PUBLIC_KEY = "YourLVLKey";
    // You should also modify this salt
    public static final byte[] SALT = new byte[] { 1, 42, -12, -1, 54, 98,
            -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84
    };

    @Override
    public String getPublicKey() {
        return BASE64_PUBLIC_KEY;
    }

    @Override
    public byte[] getSALT() {
        return SALT;
    }

    @Override
    public String getAlarmReceiverClassName() {
        return SampleAlarmReceiver.class.getName();
    }
}

सूचना: आपको BASE64_PUBLIC_KEY वैल्यू को अपने पब्लिशर खाते की सार्वजनिक कुंजी के तौर पर अपडेट करना होगा. आपको यह कुंजी, Developer Console में अपनी प्रोफ़ाइल की जानकारी में दिखेगी. डाउनलोड किए गए कॉन्टेंट की जांच करते समय भी ऐसा करना ज़रूरी है.

अपनी मेनिफ़ेस्ट फ़ाइल में सेवा के बारे में बताना न भूलें:

<app ...>
    <service android:name=".SampleDownloaderService" />
    ...
</app>

अलार्म रिसीवर लागू करना

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

DownloaderClientMarshaller.startDownloadServiceIfRequired() को कॉल करने के लिए, आपको बस onReceive() वाले तरीके को बदलना होगा.

उदाहरण के लिए:

Kotlin

class SampleAlarmReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        try {
            DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    context,
                    intent,
                    SampleDownloaderService::class.java
            )
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
    }
}

Java

public class SampleAlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            DownloaderClientMarshaller.startDownloadServiceIfRequired(context,
                intent, SampleDownloaderService.class);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}

ध्यान दें कि यह वह क्लास है जिसके लिए आपको अपनी सेवा के getAlarmReceiverClassName() तरीके में नाम दिखाना होगा (पिछला सेक्शन देखें).

अपनी मेनिफ़ेस्ट फ़ाइल में, ईमेल पाने वाले व्यक्ति की जानकारी देना न भूलें:

<app ...>
    <receiver android:name=".SampleAlarmReceiver" />
    ...
</app>

डाउनलोड शुरू करना

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

डाउनलोडर लाइब्रेरी का इस्तेमाल करके डाउनलोड शुरू करने के लिए, ये प्रोसेस पूरी करनी होंगी:

  1. देखें कि फ़ाइलें डाउनलोड हुई हैं या नहीं.

    डाउनलोडर लाइब्रेरी में Helper क्लास में कुछ एपीआई शामिल हैं, ताकि इस प्रोसेस में मदद मिल सके:

    • getExpansionAPKFileName(Context, c, boolean mainFile, int versionCode)
    • doesFileExist(Context c, String fileName, long fileSize)

    उदाहरण के लिए, APK एक्सपैंशन पैकेज में दिया गया सैंपल ऐप्लिकेशन, ऐक्टिविटी के onCreate() मैथड में इस मैथड को कॉल करता है, ताकि यह पता लगाया जा सके कि एक्सपैंशन फ़ाइलें डिवाइस पर पहले से मौजूद हैं या नहीं:

    Kotlin

    fun expansionFilesDelivered(): Boolean {
        xAPKS.forEach { xf ->
            Helpers.getExpansionAPKFileName(this, xf.isBase, xf.fileVersion).also { fileName ->
                if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false))
                    return false
            }
        }
        return true
    }

    Java

    boolean expansionFilesDelivered() {
        for (XAPKFile xf : xAPKS) {
            String fileName = Helpers.getExpansionAPKFileName(this, xf.isBase,
                xf.fileVersion);
            if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false))
                return false;
        }
        return true;
    }

    इस मामले में, हर XAPKFile ऑब्जेक्ट में किसी एक्सपैंशन फ़ाइल का वर्शन नंबर और फ़ाइल का साइज़ होता है. साथ ही, यह भी जानकारी होती है कि यह मुख्य एक्सपैंशन फ़ाइल है या नहीं. (ज़्यादा जानकारी के लिए, सैंपल ऐप्लिकेशन की SampleDownloaderActivity क्लास देखें.)

    अगर यह तरीका गलत नतीजा दिखाता है, तो ऐप्लिकेशन को डाउनलोड शुरू करना चाहिए.

  2. स्टैटिक तरीके DownloaderClientMarshaller.startDownloadServiceIfRequired(Context c, PendingIntent notificationClient, Class<?> serviceClass) को कॉल करके डाउनलोड शुरू करें.

    यह तरीका इन पैरामीटर का इस्तेमाल करता है:

    • context: आपके ऐप्लिकेशन का Context.
    • notificationClient: मुख्य गतिविधि शुरू करने के लिए PendingIntent. इसका इस्तेमाल उस Notification में किया जाता है जिसे DownloaderService, डाउनलोड की प्रोग्रेस दिखाने के लिए बनाता है. जब उपयोगकर्ता सूचना चुनता है, तो सिस्टम यहां दिए गए PendingIntent को लागू करता है. साथ ही, वह गतिविधि खोलता है जो डाउनलोड की प्रोग्रेस दिखाती है. आम तौर पर, यह वही गतिविधि होती है जिसने डाउनलोड शुरू किया था.
    • serviceClass: DownloaderService को लागू करने के लिए Class ऑब्जेक्ट. यह सेवा शुरू करने और ज़रूरत पड़ने पर डाउनलोड शुरू करने के लिए ज़रूरी है.

    यह तरीका एक पूर्णांक दिखाता है, जिससे पता चलता है कि डाउनलोड करना ज़रूरी है या नहीं. संभावित वैल्यू ये हैं:

    • NO_DOWNLOAD_REQUIRED: यह तब दिखता है, जब फ़ाइलें पहले से मौजूद हों या डाउनलोड की प्रोसेस पहले से चल रही हो.
    • LVL_CHECK_REQUIRED: अगर एक्सपैंशन फ़ाइल के यूआरएल पाने के लिए, लाइसेंस की पुष्टि करना ज़रूरी है, तो यह वैल्यू दिखती है.
    • DOWNLOAD_REQUIRED: यह तब दिखता है, जब एक्सपैंशन फ़ाइल के यूआरएल पहले से ही मौजूद हों, लेकिन उन्हें डाउनलोड न किया गया हो.

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

    उदाहरण के लिए:

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        // Check if expansion files are available before going any further
        if (!expansionFilesDelivered()) {
            val pendingIntent =
                    // Build an Intent to start this activity from the Notification
                    Intent(this, MainActivity::class.java).apply {
                        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
                    }.let { notifierIntent ->
                        PendingIntent.getActivity(
                                this,
                                0,
                                notifierIntent,
                                PendingIntent.FLAG_UPDATE_CURRENT
                        )
                    }
    
    
            // Start the download service (if required)
            val startResult: Int = DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    this,
                    pendingIntent,
                    SampleDownloaderService::class.java
            )
            // If download has started, initialize this activity to show
            // download progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // This is where you do set up to display the download
                // progress (next step)
                ...
                return
            } // If the download wasn't necessary, fall through to start the app
        }
        startApp() // Expansion files are available, start the app
    }

    Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Check if expansion files are available before going any further
        if (!expansionFilesDelivered()) {
            // Build an Intent to start this activity from the Notification
            Intent notifierIntent = new Intent(this, MainActivity.getClass());
            notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                                    Intent.FLAG_ACTIVITY_CLEAR_TOP);
            ...
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                    notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    
            // Start the download service (if required)
            int startResult =
                DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                            pendingIntent, SampleDownloaderService.class);
            // If download has started, initialize this activity to show
            // download progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // This is where you do set up to display the download
                // progress (next step)
                ...
                return;
            } // If the download wasn't necessary, fall through to start the app
        }
        startApp(); // Expansion files are available, start the app
    }
  3. जब startDownloadServiceIfRequired() मेथड NO_DOWNLOAD_REQUIRED के अलावा कुछ और दिखाता है, तो DownloaderClientMarshaller.CreateStub(IDownloaderClient client, Class<?> downloaderService) को कॉल करके IStub का एक इंस्टेंस बनाएं. IStub, आपकी गतिविधि को डाउनलोड करने वाली सेवा से जोड़ता है, ताकि आपकी गतिविधि को डाउनलोड की प्रोग्रेस के बारे में कॉलबैक मिल सकें.

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

    हमारा सुझाव है कि startDownloadServiceIfRequired() के डाउनलोड शुरू होने के बाद, अपनी गतिविधि के onCreate() तरीके के दौरान, IStub को इंस्टैंशिएट करने के लिए CreateStub() को कॉल करें.

    उदाहरण के लिए, onCreate() के लिए दिए गए पिछले कोड सैंपल में, startDownloadServiceIfRequired() के नतीजे का जवाब इस तरह दिया जा सकता है:

    Kotlin

            // Start the download service (if required)
            val startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    this@MainActivity,
                    pendingIntent,
                    SampleDownloaderService::class.java
            )
            // If download has started, initialize activity to show progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // Instantiate a member instance of IStub
                downloaderClientStub =
                        DownloaderClientMarshaller.CreateStub(this, SampleDownloaderService::class.java)
                // Inflate layout that shows download progress
                setContentView(R.layout.downloader_ui)
                return
            }

    Java

            // Start the download service (if required)
            int startResult =
                DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                            pendingIntent, SampleDownloaderService.class);
            // If download has started, initialize activity to show progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // Instantiate a member instance of IStub
                downloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
                        SampleDownloaderService.class);
                // Inflate layout that shows download progress
                setContentView(R.layout.downloader_ui);
                return;
            }

    onCreate() तरीका वापस आने के बाद, आपकी गतिविधि को onResume() पर कॉल मिलता है. इसके बाद, आपको IStub पर connect() को कॉल करना चाहिए और उसे अपने ऐप्लिकेशन का Context देना चाहिए. इसके उलट, आपको अपनी गतिविधि के onStop() कॉलबैक में disconnect() को कॉल करना चाहिए.

    Kotlin

    override fun onResume() {
        downloaderClientStub?.connect(this)
        super.onResume()
    }
    
    override fun onStop() {
        downloaderClientStub?.disconnect(this)
        super.onStop()
    }

    Java

    @Override
    protected void onResume() {
        if (null != downloaderClientStub) {
            downloaderClientStub.connect(this);
        }
        super.onResume();
    }
    
    @Override
    protected void onStop() {
        if (null != downloaderClientStub) {
            downloaderClientStub.disconnect(this);
        }
        super.onStop();
    }

    IStub पर connect() को कॉल करने से, आपकी गतिविधि DownloaderService से जुड़ जाती है. इससे आपकी गतिविधि को IDownloaderClient इंटरफ़ेस के ज़रिए, डाउनलोड की स्थिति में हुए बदलावों के बारे में कॉलबैक मिलते हैं.

डाउनलोड की प्रोग्रेस

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

IDownloaderClient के लिए, इंटरफ़ेस के ये तरीके ज़रूरी हैं:

onServiceConnected(Messenger m)
अपनी गतिविधि में IStub को इंस्टैंशिएट करने के बाद, आपको इस विधि का कॉल मिलेगा. यह DownloaderService के आपके इंस्टेंस से जुड़ा Messenger ऑब्जेक्ट पास करता है. सेवा से जुड़े अनुरोध भेजने के लिए, आपको DownloaderServiceMarshaller.CreateProxy() पर कॉल करना होगा. इससे आपको सेवा से जुड़ा IDownloaderService इंटरफ़ेस मिलेगा. इस इंटरफ़ेस की मदद से, डाउनलोड को रोका और फिर से शुरू किया जा सकता है.

लागू करने का सुझाव इस तरह दिखता है:

Kotlin

private var remoteService: IDownloaderService? = null
...

override fun onServiceConnected(m: Messenger) {
    remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply {
        downloaderClientStub?.messenger?.also { messenger ->
            onClientUpdated(messenger)
        }
    }
}

Java

private IDownloaderService remoteService;
...

@Override
public void onServiceConnected(Messenger m) {
    remoteService = DownloaderServiceMarshaller.CreateProxy(m);
    remoteService.onClientUpdated(downloaderClientStub.getMessenger());
}

IDownloaderService ऑब्जेक्ट को शुरू करने के बाद, डाउनलोड करने की सेवा को निर्देश भेजे जा सकते हैं. जैसे, डाउनलोड को रोकना और फिर से शुरू करना (requestPauseDownload() और requestContinueDownload()).

onDownloadStateChanged(int newState)
डाउनलोड की स्थिति में बदलाव होने पर, डाउनलोड सेवा इस फ़ंक्शन को कॉल करती है. जैसे, डाउनलोड शुरू या पूरा होने पर.

newState वैल्यू, IDownloaderClient क्लास की STATE_* स्थिर वैल्यू में बताई गई कई संभावित वैल्यू में से एक होगी.

अपने उपयोगकर्ताओं को काम का मैसेज देने के लिए, Helpers.getDownloaderStringResourceIDFromState() को कॉल करके हर स्थिति के लिए, उससे जुड़ी स्ट्रिंग का अनुरोध किया जा सकता है. यह डाउनलोडर लाइब्रेरी के साथ बंडल की गई किसी स्ट्रिंग का रिसॉर्स आईडी दिखाता है. उदाहरण के लिए, "रोमिंग की वजह से, डाउनलोड रोक दिया गया" स्ट्रिंग, STATE_PAUSED_ROAMING से जुड़ी है.

onDownloadProgress(DownloadProgressInfo progress)
डाउनलोड सेवा, DownloadProgressInfo ऑब्जेक्ट डिलीवर करने के लिए इसे कॉल करती है. इसमें डाउनलोड की प्रोग्रेस के बारे में अलग-अलग जानकारी होती है. जैसे, बचे हुए अनुमानित समय, मौजूदा स्पीड, पूरी प्रोग्रेस, और कुल डाउनलोड की गई फ़ाइल का साइज़. इससे, डाउनलोड की प्रोग्रेस का यूज़र इंटरफ़ेस (यूआई) अपडेट किया जा सकता है.

सलाह: डाउनलोड की प्रोग्रेस के यूज़र इंटरफ़ेस (यूआई) को अपडेट करने वाले इन कॉलबैक के उदाहरणों के लिए, APK एक्सपैंशन पैकेज के साथ दिए गए सैंपल ऐप्लिकेशन में SampleDownloaderActivity देखें.

IDownloaderService इंटरफ़ेस के लिए, यहां कुछ सार्वजनिक तरीके दिए गए हैं जो शायद आपके काम के हों:

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

Kotlin

remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply {
    ...
    setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR)
}

Java

remoteService
    .setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR);

APKExpansionPolicy का इस्तेमाल करना

अगर आपको Google Play की डाउनलोड करने की लाइब्रेरी का इस्तेमाल करने के बजाय, अपनी डाउनलोड करने की सेवा बनानी है, तो भी आपको लाइसेंस की पुष्टि करने वाली लाइब्रेरी में दिए गए APKExpansionPolicy का इस्तेमाल करना चाहिए. APKExpansionPolicy क्लास, ServerManagedPolicy क्लास से काफ़ी हद तक मिलती-जुलती है. ServerManagedPolicy क्लास, Google Play लाइसेंस की पुष्टि करने वाली लाइब्रेरी में उपलब्ध है. हालांकि, APKExpansionPolicy क्लास में APK एक्सपैंशन फ़ाइल के रिस्पॉन्स एक्सट्रा के लिए, अतिरिक्त हैंडल करने की सुविधा शामिल होती है.

ध्यान दें: अगर पिछले सेक्शन में बताए गए तरीके से डाउनलोडर लाइब्रेरी का इस्तेमाल किया जाता है, तो लाइब्रेरी APKExpansionPolicy के साथ सभी इंटरैक्शन करती है. इसलिए, आपको इस क्लास का सीधे तौर पर इस्तेमाल करने की ज़रूरत नहीं है.

इस क्लास में, उपलब्ध एक्सपैंशन फ़ाइलों के बारे में ज़रूरी जानकारी पाने के तरीके शामिल हैं:

  • getExpansionURLCount()
  • getExpansionURL(int index)
  • getExpansionFileName(int index)
  • getExpansionFileSize(int index)

Downloader Library का इस्तेमाल करने पर, APKExpansionPolicy का इस्तेमाल करने के तरीके के बारे में ज़्यादा जानने के लिए, अपने ऐप्लिकेशन में लाइसेंस जोड़ना दस्तावेज़ देखें. इसमें, इस तरह की लाइसेंस नीति को लागू करने का तरीका बताया गया है.

एक्सपैंशन फ़ाइल को पढ़ना

APK एक्सपैंशन फ़ाइलें डिवाइस पर सेव होने के बाद, फ़ाइलों को पढ़ने का तरीका, इस्तेमाल की गई फ़ाइल के टाइप पर निर्भर करता है. खास जानकारी में बताए गए तरीके के मुताबिक, आपकी एक्सपैंशन फ़ाइलें किसी भी तरह की हो सकती हैं. हालांकि, इनका नाम बदलकर, फ़ाइल के नाम के किसी खास फ़ॉर्मैट का इस्तेमाल किया जाता है. साथ ही, इन्हें <shared-storage>/Android/obb/<package-name>/ में सेव किया जाता है.

फ़ाइलों को पढ़ने का तरीका चाहे जो भी हो, आपको हमेशा यह देखना चाहिए कि बाहरी स्टोरेज, पढ़ने के लिए उपलब्ध है या नहीं. ऐसा हो सकता है कि उपयोगकर्ता ने स्टोरेज को यूएसबी के ज़रिए कंप्यूटर से माउंट किया हो या उसने एसडी कार्ड को हटा दिया हो.

ध्यान दें: ऐप्लिकेशन शुरू होने पर, आपको हमेशा यह देखना चाहिए कि getExternalStorageState() को कॉल करके, बाहरी स्टोरेज में जगह उपलब्ध है या नहीं और उसमें मौजूद डेटा को पढ़ा जा सकता है या नहीं. यह कई संभावित स्ट्रिंग में से एक दिखाता है, जो बाहरी स्टोरेज की स्थिति दिखाती है. आपके ऐप्लिकेशन में इसे पढ़ा जा सके, इसके लिए रिटर्न वैल्यू MEDIA_MOUNTED होनी चाहिए.

फ़ाइलों के नाम पाना

खास जानकारी में बताया गया है कि APK एक्सपैंशन फ़ाइलों को, फ़ाइल के नाम के किसी खास फ़ॉर्मैट का इस्तेमाल करके सेव किया जाता है:

[main|patch].<expansion-version>.<package-name>.obb

एक्सपैंशन फ़ाइलों की जगह और नाम पाने के लिए, आपको अपनी फ़ाइलों का पाथ बनाने के लिए, getExternalStorageDirectory() और getPackageName() तरीकों का इस्तेमाल करना चाहिए.

यहां एक तरीका बताया गया है जिसका इस्तेमाल करके, अपने ऐप्लिकेशन में एक ऐरे पाया जा सकता है. इसमें, आपकी दोनों एक्सपैंशन फ़ाइलों का पूरा पाथ शामिल होता है:

Kotlin

fun getAPKExpansionFiles(ctx: Context, mainVersion: Int, patchVersion: Int): Array<String> {
    val packageName = ctx.packageName
    val ret = mutableListOf<String>()
    if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
        // Build the full path to the app's expansion files
        val root = Environment.getExternalStorageDirectory()
        val expPath = File(root.toString() + EXP_PATH + packageName)

        // Check that expansion file path exists
        if (expPath.exists()) {
            if (mainVersion > 0) {
                val strMainPath = "$expPath${File.separator}main.$mainVersion.$packageName.obb"
                val main = File(strMainPath)
                if (main.isFile) {
                    ret += strMainPath
                }
            }
            if (patchVersion > 0) {
                val strPatchPath = "$expPath${File.separator}patch.$mainVersion.$packageName.obb"
                val main = File(strPatchPath)
                if (main.isFile) {
                    ret += strPatchPath
                }
            }
        }
    }
    return ret.toTypedArray()
}

Java

// The shared path to all app expansion files
private final static String EXP_PATH = "/Android/obb/";

static String[] getAPKExpansionFiles(Context ctx, int mainVersion,
      int patchVersion) {
    String packageName = ctx.getPackageName();
    Vector<String> ret = new Vector<String>();
    if (Environment.getExternalStorageState()
          .equals(Environment.MEDIA_MOUNTED)) {
        // Build the full path to the app's expansion files
        File root = Environment.getExternalStorageDirectory();
        File expPath = new File(root.toString() + EXP_PATH + packageName);

        // Check that expansion file path exists
        if (expPath.exists()) {
            if ( mainVersion > 0 ) {
                String strMainPath = expPath + File.separator + "main." +
                        mainVersion + "." + packageName + ".obb";
                File main = new File(strMainPath);
                if ( main.isFile() ) {
                        ret.add(strMainPath);
                }
            }
            if ( patchVersion > 0 ) {
                String strPatchPath = expPath + File.separator + "patch." +
                        mainVersion + "." + packageName + ".obb";
                File main = new File(strPatchPath);
                if ( main.isFile() ) {
                        ret.add(strPatchPath);
                }
            }
        }
    }
    String[] retArray = new String[ret.size()];
    ret.toArray(retArray);
    return retArray;
}

इस तरीके को कॉल करने के लिए, अपने ऐप्लिकेशन Context और एक्सपैंशन फ़ाइल के पसंदीदा वर्शन को पास करें.

एक्सपैंशन फ़ाइल के वर्शन नंबर का पता लगाने के कई तरीके हैं. एक आसान तरीका यह है कि APKExpansionPolicy क्लास के getExpansionFileName(int index) तरीके का इस्तेमाल करके, एक्सपैंशन फ़ाइल के नाम से क्वेरी करके, डाउनलोड शुरू होने पर वर्शन को SharedPreferences फ़ाइल में सेव करें. इसके बाद, जब आपको एक्सपैंशन फ़ाइल ऐक्सेस करनी हो, तो SharedPreferences फ़ाइल को पढ़कर वर्शन कोड पाया जा सकता है.

शेयर किए गए स्टोरेज से डेटा पढ़ने के बारे में ज़्यादा जानने के लिए, डेटा स्टोरेज के दस्तावेज़ देखें.

APK एक्सपैंशन की ज़िप लाइब्रेरी का इस्तेमाल करना

Google Market के APK एक्सपैंशन पैकेज में, APK एक्सपैंशन Zip लाइब्रेरी (<sdk>/extras/google/google_market_apk_expansion/zip_file/ में मौजूद) नाम की एक लाइब्रेरी शामिल होती है. यह लाइब्रेरी ज़रूरी नहीं है. इसका इस्तेमाल, एक्सपैंशन फ़ाइलों को ZIP फ़ाइलों के तौर पर सेव करने पर किया जाता है. इस लाइब्रेरी का इस्तेमाल करके, वर्चुअल फ़ाइल सिस्टम के तौर पर अपनी ZIP एक्सपैंशन फ़ाइलों से संसाधनों को आसानी से पढ़ा जा सकता है.

APK एक्सपैंशन ZIP लाइब्रेरी में ये क्लास और एपीआई शामिल हैं:

APKExpansionSupport
एक्सपैंशन फ़ाइल के नाम और ZIP फ़ाइलों को ऐक्सेस करने के कुछ तरीके उपलब्ध कराता है:
getAPKExpansionFiles()
यह वही तरीका है जो ऊपर दिखाया गया है. यह दोनों एक्सपैंशन फ़ाइलों का पूरा फ़ाइल पाथ दिखाता है.
getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion)
यह एक ZipResourceFile दिखाता है, जो मुख्य फ़ाइल और पैच फ़ाइल, दोनों का योग होता है. इसका मतलब है कि अगर आपने mainVersion और patchVersion, दोनों की जानकारी दी है, तो यह एक ZipResourceFile दिखाता है. इससे पूरे डेटा को पढ़ने का ऐक्सेस मिलता है. साथ ही, पैच फ़ाइल का डेटा, मुख्य फ़ाइल में मर्ज हो जाता है.
ZipResourceFile
शेयर किए गए स्टोरेज में मौजूद ZIP फ़ाइल को दिखाता है. साथ ही, आपकी ZIP फ़ाइलों के आधार पर वर्चुअल फ़ाइल सिस्टम उपलब्ध कराने के लिए, सभी काम करता है. APKExpansionSupport.getAPKExpansionZipFile() का इस्तेमाल करके या ZipResourceFile के साथ अपनी एक्सपैंशन फ़ाइल का पाथ देकर, इंस्टेंस पाया जा सकता है. इस क्लास में कई काम के तरीके शामिल हैं, लेकिन आम तौर पर आपको ज़्यादातर तरीकों को ऐक्सेस करने की ज़रूरत नहीं होती. कुछ अहम तरीके यहां बताए गए हैं:
getInputStream(String assetPath)
ZIP फ़ाइल में मौजूद फ़ाइल को पढ़ने के लिए InputStream उपलब्ध कराता है. assetPath, ZIP फ़ाइल के कॉन्टेंट के रूट के हिसाब से, अपनी पसंद की फ़ाइल का पाथ होना चाहिए.
getAssetFileDescriptor(String assetPath)
ZIP फ़ाइल में मौजूद किसी फ़ाइल के लिए AssetFileDescriptor उपलब्ध कराता है. assetPath, ZIP फ़ाइल के कॉन्टेंट के रूट के हिसाब से, अपनी पसंद की फ़ाइल का पाथ होना चाहिए. यह कुछ Android API के लिए काम का है. जैसे, कुछ MediaPlayer एपीआई के लिए AssetFileDescriptor की ज़रूरत होती है.
APEZProvider
ज़्यादातर ऐप्लिकेशन को इस क्लास का इस्तेमाल करने की ज़रूरत नहीं होती. इस क्लास में एक ContentProvider के बारे में बताया गया है, जो कॉन्टेंट उपलब्ध कराने वाली कंपनी Uri के ज़रिए, ZIP फ़ाइलों से डेटा को मार्शल करता है. ऐसा इसलिए किया जाता है, ताकि कुछ Android API को फ़ाइल का ऐक्सेस दिया जा सके. ये ऐसे Android API होते हैं जो मीडिया फ़ाइलों का Uri ऐक्सेस चाहते हैं. उदाहरण के लिए, अगर आपको VideoView.setVideoURI() की मदद से कोई वीडियो चलाना है, तो यह सुविधा काम की है.

मीडिया फ़ाइलों को ZIP फ़ॉर्मैट में कंप्रेस न करना

अगर मीडिया फ़ाइलों को सेव करने के लिए एक्सपैंशन फ़ाइलों का इस्तेमाल किया जा रहा है, तो ZIP फ़ाइल में भी Android मीडिया चलाने के उन कॉल का इस्तेमाल किया जा सकता है जो ऑफ़सेट और लंबाई कंट्रोल (जैसे, MediaPlayer.setDataSource() और SoundPool.load()) की सुविधा देते हैं. इसके लिए, ZIP पैकेज बनाते समय मीडिया फ़ाइलों को ज़्यादा कंप्रेस नहीं करना चाहिए. उदाहरण के लिए, zip टूल का इस्तेमाल करते समय, आपको उन फ़ाइल के सफ़िक्स बताने के लिए -n विकल्प का इस्तेमाल करना चाहिए जिन्हें कंप्रेस नहीं करना है:

zip -n .mp4;.ogg main_expansion media_files

ZIP फ़ाइल से डेटा पढ़ना

APK एक्सपैंशन ज़िप लाइब्रेरी का इस्तेमाल करते समय, आम तौर पर अपनी ज़िप फ़ाइल से कोई फ़ाइल पढ़ने के लिए, इन चीज़ों की ज़रूरत होती है:

Kotlin

// Get a ZipResourceFile representing a merger of both the main and patch files
val expansionFile =
        APKExpansionSupport.getAPKExpansionZipFile(appContext, mainVersion, patchVersion)

// Get an input stream for a known file inside the expansion file ZIPs
expansionFile.getInputStream(pathToFileInsideZip).use {
    ...
}

Java

// Get a ZipResourceFile representing a merger of both the main and patch files
ZipResourceFile expansionFile =
    APKExpansionSupport.getAPKExpansionZipFile(appContext,
        mainVersion, patchVersion);

// Get an input stream for a known file inside the expansion file ZIPs
InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);

ऊपर दिया गया कोड, आपकी मुख्य एक्सपैंशन फ़ाइल या पैच एक्सपैंशन फ़ाइल में मौजूद किसी भी फ़ाइल का ऐक्सेस देता है. इसके लिए, यह दोनों फ़ाइलों की सभी फ़ाइलों के मर्ज किए गए मैप को पढ़ता है. getAPKExpansionFile() का तरीका बताने के लिए, आपको सिर्फ़ अपने ऐप्लिकेशन android.content.Context और मुख्य एक्सपैंशन फ़ाइल और पैच एक्सपैंशन फ़ाइल, दोनों का वर्शन नंबर देना होगा.

अगर आपको किसी खास एक्सपैंशन फ़ाइल से पढ़ना है, तो ZipResourceFile कन्स्ट्रक्टर का इस्तेमाल करें. इसके लिए, अपनी पसंद की एक्सपैंशन फ़ाइल का पाथ डालें:

Kotlin

// Get a ZipResourceFile representing a specific expansion file
val expansionFile = ZipResourceFile(filePathToMyZip)

// Get an input stream for a known file inside the expansion file ZIPs
expansionFile.getInputStream(pathToFileInsideZip).use {
    ...
}

Java

// Get a ZipResourceFile representing a specific expansion file
ZipResourceFile expansionFile = new ZipResourceFile(filePathToMyZip);

// Get an input stream for a known file inside the expansion file ZIPs
InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);

एक्सपैंशन फ़ाइलों के लिए इस लाइब्रेरी का इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, सैंपल ऐप्लिकेशन की SampleDownloaderActivity क्लास देखें. इसमें सीआरसी का इस्तेमाल करके, डाउनलोड की गई फ़ाइलों की पुष्टि करने के लिए अतिरिक्त कोड शामिल होता है. ध्यान रखें कि अगर इस सैंपल को अपने लागू करने के आधार के तौर पर इस्तेमाल किया जाता है, तो आपको xAPKS कलेक्शन में अपनी एक्सपैंशन फ़ाइलों का बाइट साइज़ बताना होगा.

एक्सपैंशन फ़ाइलों की जांच करना

अपना ऐप्लिकेशन पब्लिश करने से पहले, आपको दो चीज़ों की जांच करनी चाहिए: एक्सपैंशन फ़ाइलें पढ़ना और फ़ाइलें डाउनलोड करना.

फ़ाइल पढ़ने की सुविधा की जांच करना

Google Play पर अपना ऐप्लिकेशन अपलोड करने से पहले, आपको यह जांच करनी चाहिए कि आपका ऐप्लिकेशन, शेयर किए गए स्टोरेज में मौजूद फ़ाइलों को पढ़ सकता है या नहीं. आपको बस डिवाइस के शेयर किए गए स्टोरेज में, फ़ाइलों को सही जगह पर जोड़ना होगा और अपना ऐप्लिकेशन लॉन्च करना होगा:

  1. अपने डिवाइस पर, शेयर किए गए स्टोरेज में सही डायरेक्ट्री बनाएं. Google Play आपकी फ़ाइलों को इसी डायरेक्ट्री में सेव करेगा.

    उदाहरण के लिए, अगर आपके पैकेज का नाम com.example.android है, तो आपको शेयर किए गए स्टोरेज में Android/obb/com.example.android/ डायरेक्ट्री बनानी होगी. (शेयर किए गए स्टोरेज को माउंट करने के लिए, अपने टेस्ट डिवाइस को कंप्यूटर से कनेक्ट करें और मैन्युअल तरीके से यह डायरेक्ट्री बनाएं.)

  2. एक्सपैंशन फ़ाइलों को मैन्युअल तरीके से उस डायरेक्ट्री में जोड़ें. पक्का करें कि आपने अपनी फ़ाइलों का नाम बदलकर, फ़ाइल के नाम के उस फ़ॉर्मैट से मैच किया हो जिसका इस्तेमाल Google Play करेगा.

    उदाहरण के लिए, फ़ाइल टाइप चाहे जो भी हो, com.example.android ऐप्लिकेशन के लिए मुख्य एक्सपैंशन फ़ाइल main.0300110.com.example.android.obb होनी चाहिए. वर्शन कोड में अपनी पसंद की कोई भी वैल्यू दी जा सकती है. बस याद रखें:

    • मुख्य एक्सपैंशन फ़ाइल हमेशा main से शुरू होती है और पैच फ़ाइल patch से शुरू होती है.
    • पैकेज का नाम हमेशा उस APK से मेल खाता है जिससे फ़ाइल को Google Play पर अटैच किया गया है.
  3. एक्सपैंशन फ़ाइलें डिवाइस पर मौजूद होने के बाद, ऐप्लिकेशन को इंस्टॉल करके चलाया जा सकता है, ताकि एक्सपैंशन फ़ाइलों की जांच की जा सके.

एक्सपैंशन फ़ाइलों को मैनेज करने के बारे में कुछ रिमाइंडर यहां दिए गए हैं:

  • .obb एक्सपैंशन फ़ाइलों को न तो मिटाएं और न ही उनका नाम बदलें. भले ही, आपने डेटा को किसी दूसरी जगह पर अनपैक किया हो. ऐसा करने पर, Google Play (या आपका ऐप्लिकेशन) बार-बार एक्सपैंशन फ़ाइल डाउनलोड करेगा.
  • अपनी obb/ Directory में कोई अन्य डेटा सेव न करें. अगर आपको कुछ डेटा अनपैक करना है, तो उसे getExternalFilesDir() की बताई गई जगह पर सेव करें.

फ़ाइल डाउनलोड करने की सुविधा की जांच करना

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

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

ध्यान दें: पहले, किसी ऐप्लिकेशन को टेस्ट करने के लिए, पब्लिश नहीं किया गया "ड्राफ़्ट" वर्शन अपलोड किया जा सकता था. यह सुविधा अब काम नहीं करती. इसके बजाय, आपको इसे इंटरनल, क्लोज़्ड या ओपन टेस्टिंग ट्रैक पर पब्लिश करना होगा. ज़्यादा जानकारी के लिए, ड्राफ़्ट ऐप्लिकेशन अब काम नहीं करते लेख पढ़ें.

ऐप्लिकेशन अपडेट करना

Google Play पर एक्सपैंशन फ़ाइलों का इस्तेमाल करने का एक बड़ा फ़ायदा यह है कि इससे सभी ओरिजनल एसेट को फिर से डाउनलोड किए बिना, अपने ऐप्लिकेशन को अपडेट किया जा सकता है. Google Play पर हर APK के साथ दो एक्सपैंशन फ़ाइलें दी जा सकती हैं. इसलिए, दूसरी फ़ाइल को "पैच" के तौर पर इस्तेमाल किया जा सकता है. इससे अपडेट और नई एसेट मिलती हैं. ऐसा करने से, मुख्य एक्सपैंशन फ़ाइल को फिर से डाउनलोड करने की ज़रूरत नहीं पड़ती. यह फ़ाइल, उपयोगकर्ताओं के लिए बड़ी और महंगी हो सकती है.

तकनीकी तौर पर, पैच एक्सपैंशन फ़ाइल और मुख्य एक्सपैंशन फ़ाइल एक ही होती हैं. साथ ही, Android सिस्टम और Google Play, मुख्य और पैच एक्सपैंशन फ़ाइलों के बीच असल पैचिंग नहीं करते. आपके ऐप्लिकेशन कोड को ज़रूरी पैच खुद करने चाहिए.

अगर एक्सपैंशन फ़ाइलों के तौर पर ZIP फ़ाइलों का इस्तेमाल किया जाता है, तो APK एक्सपैंशन पैकेज में शामिल APK एक्सपैंशन ज़िप लाइब्रेरी की मदद से, अपनी पैच फ़ाइल को मुख्य एक्सपैंशन फ़ाइल के साथ मर्ज किया जा सकता है.

ध्यान दें: अगर आपको सिर्फ़ पैच एक्सपैंशन फ़ाइल में बदलाव करने हैं, तब भी आपको APK अपडेट करना होगा, ताकि Google Play ऐप्लिकेशन को अपडेट कर सके. अगर आपको ऐप्लिकेशन में कोड में बदलाव करने की ज़रूरत नहीं है, तो आपको सिर्फ़ मेनिफ़ेस्ट में versionCode को अपडेट करना चाहिए.

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

एक्सपैंशन फ़ाइलों में अपडेट करने के बारे में ध्यान रखने वाली कुछ बातें यहां दी गई हैं:

  • आपके ऐप्लिकेशन के लिए, एक बार में सिर्फ़ दो एक्सपैंशन फ़ाइलें हो सकती हैं. एक मुख्य एक्सपैंशन फ़ाइल और एक पैच एक्सपैंशन फ़ाइल. किसी फ़ाइल को अपडेट करने के दौरान, Google Play उसका पिछला वर्शन मिटा देता है. इसलिए, मैन्युअल तरीके से अपडेट करते समय, आपके ऐप्लिकेशन को भी ऐसा करना होगा.
  • पैच एक्सपैंशन फ़ाइल जोड़ने पर, Android सिस्टम आपके ऐप्लिकेशन या मुख्य एक्सपैंशन फ़ाइल को पैच नहीं करता. आपको अपने ऐप्लिकेशन को पैच डेटा के साथ काम करने के लिए डिज़ाइन करना होगा. हालांकि, APK एक्सपैंशन पैकेज में, एक्सपैंशन फ़ाइलों के तौर पर ZIP फ़ाइलों का इस्तेमाल करने के लिए एक लाइब्रेरी शामिल होती है. यह लाइब्रेरी, पैच फ़ाइल के डेटा को मुख्य एक्सपैंशन फ़ाइल में मर्ज करती है, ताकि आप एक्सपैंशन फ़ाइल का सारा डेटा आसानी से पढ़ सकें.