Development environment.
- Ubuntu 11.10 (Oneiric)
- JDK 1.6.0_24-b07
- Eclipse 3.7.3 (Indigo)
- Android Development Toolkit 17.0.0
Preparing.
- Get a publisher account here for Google Play, if you don't have yet.
- Download two packages from the SDK Manager.('Google Play APK Expansion Library' and 'Google Play Licensing Library')
Android SDK Manager - Create two library projects from existing source.
- <sdk>/extras/google/play_apk_expansion/downloader_library
- <sdk>/extras/google/play_licensing/library
- Create a new project which you want to use APK Expansion Files and add above two library project to your new project's build path.
Add a reference to a library project
Implementing.
- Downloader service.
// Extends com.google.android.vending.expansion.downloader.impl.DownloaderService class and override three methods. public class ExpansionFileDownloaderService extends DownloaderService { // the Base64-encoded RSA public key for your publisher account private static final String PUBLIC_KEY = "{YOU_PUBLIC_KEY}"; // Generate 20 random bytes, and put them here. private static final byte[] SALT = new byte[] {}; @Override public String getPublicKey() { return PUBLIC_KEY; } @Override public byte[] getSALT() { return SALT; } @Override public String getAlarmReceiverClassName() { return ExpansionFileAlarmReceiver.class.getName(); } }
- Alarm receiver.
public class ExpansionFileAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { try { DownloaderClientMarshaller.startDownloadServiceIfRequired( context, intent, ExpansionFileDownloaderService.class); } catch (NameNotFoundException e) { Log.e("apk-expansion-files", "NameNotFoundException occurred. " + e.getMessage(), e); } } }
- Main activity.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Check whether the file have been downloaded. String mainFileName = Helpers.getExpansionAPKFileName(this, true, 1); boolean fileExists = Helpers.doesFileExist(this, mainFileName, 32921796L, false); if (!fileExists) { Intent launcher = getIntent(); Intent fromNotification = new Intent(this, getClass()); fromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); fromNotification.setAction(launcher.getAction()); if (launcher.getCategories() != null) { for (String cat : launcher.getCategories()) { fromNotification.addCategory(cat); } } PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, fromNotification, PendingIntent.FLAG_UPDATE_CURRENT); try { // Start the download int result = DownloaderClientMarshaller.startDownloadServiceIfRequired( this, pendingIntent, ExpansionFileDownloaderService.class); if (DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED != result) { // implement Downloading UI. return; } } catch (NameNotFoundException e) { Log.e("apk-expansion-files", "NameNotFoundException occurred. " + e.getMessage(), e); } } // expansion file is available. start your application. }
Manifest declarations.
- uses-permission
<!-- Required to access Android Market Licensing --> <uses-permission android:name="com.android.vending.CHECK_LICENSE" /> <!-- Required to download files from Android Market --> <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" />
- application
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".ExpansionFileDownloaderService" android:label="@string/app_name" /> <receiver android:name=".ExpansionFileAlarmReceiver" android:label="@string/app_name" /> </application>
Testing APK Expansion Files
- Upload the application APK file and Expansion Files using the Google Play Developer Console.
Uploading APK and Expansion file. - Fill in the necessary application details. Click the Save button. Do not click Publish.
- Install the application on your test device and launch the app. Download will start soon.
/extras/google/play_apk_expansion/downloader_library
返信削除i tried to import downloder library but I am getting red line on import statement below;
import com.android.vending.expansion.downloader.R;
also "R cannot be resolved to a variable" problem on some of the classes like Helper.java, DownloaderService.java, DownloaderNotification, V11CustomNotification & V3CustomNotification.
it would be really kind of you if can show steps to import those projects.
Please make sure that the 'downloader_library' project is set up as a 'Android library project'. If not, R.class is never created in Gen directory. See also: http://developer.android.com/guide/developing/projects/index.html#LibraryProjects
削除Thanks a lot for your reply!
返信削除I checked, the ‘downloader_library' project is set up as 'Android library project'.
Before I setting the target of the as 2.2 therefore I was getting an errors on several classes then when I tried to import with default target, an errors disappear.
But when I actually linked the ‘downloader_library’ with my project I getting following errors;
/android-sdk-macosx/extras/google/play_apk_expansion/downloader_library/res/values-v9/styles.xml:3: error: Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.StatusBar.EventContent'.
[2012-04-26 10:04:41 - abc] /Users/mq/Documents/android-sdk-macosx/extras/google/play_apk_expansion/downloader_library/res/values-v9/styles.xml:4: error: Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.StatusBar.EventContent.Title'.
I noticed that I when remove ‘values-v9’ folder from downloader library project all the errors seems to disappear from my actual app.
I guessing its definitely something to do with values-v9’ folder. Currently my application target set to Android 2.2, API LEVEL 8 and ‘downloader_library' API Android 4.0.3, API LEVEL 15.
If you don’t mind could you please upload your above sample projects as zip?
Okey, i uploaded my sample project below.
削除http://maiware.net/samples/
I have a question. How can I handle the moment when download is completed?
返信削除When download is completed, "DownloaderService" class will send a "PendingIntent". This "Intent" class is "DownloaderClientMarshaller#startDownloadServiceIfRequired" method's second parameter. (see also: http://developer.android.com/guide/google/play/expansion-files.html "2.Start the download by calling the static method"
削除Hi Thanks for the tutorial when am trying to run your project by using my publisher account key , i am getting exception like following
返信削除can you please help me to resolve this and i have uploaded build to my account as draft and uploaded main expansion file.
11-23 13:14:57.030: E/AndroidRuntime(3271): java.lang.IllegalArgumentException: salt.length == 0
11-23 13:14:57.030: E/AndroidRuntime(3271): at javax.crypto.spec.PBEKeySpec.(PBEKeySpec.java:79)
Ah... see "ExpansionFileDownloaderService.java" (extends DownloaderService). And implement "SALT" variable like this,
削除"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};".
Hi thanks working now and after downloaded succesfully the expansion files how can i read them ,my expansion files contains images.could you please suggest me.
削除Thanks in Advance...
Hi ,
返信削除I have added apk expansion files to my app ,and am downloading apk expansion files sucessfully, i have only main expansion files ,and when am trying to read apk expansion files am getting stream as null.
Note : My apk expansion files having images.While uoploading i have zipped the images and uploaded.
Can anyone please help me out.
ZipResourceFile expansionFile = APKExpansionSupport
.getAPKExpansionZipFile(context, 1, 0);
// Get an input stream for a known file inside the expansion file
// ZIPs
InputStream is = expansionFile.getInputStream("95065668.jpg");
Log.d(TAG,
"Assigning obb image to preview image::::::::::::"
+ is.available());
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap b = BitmapFactory.decodeStream(is, null, bfo);
myimage.setBitmap(b);
Hello! I have a question, how do I get the public key from the keystore?
返信削除