1page.title=Creating Multiple APKs with 2+ Dimensions 2parent.title=Maintaining Multiple APKs 3parent.link=index.html 4 5trainingnavtop=true 6previous.title=Creating Multiple APKs for Different GL Textures 7previous.link=texture.html 8 9@jd:body 10 11<style> 12.blueCell { background-color: #9fc5e8;} 13.greenCell { background-color: #b6d7a8;} 14.redCell { background-color: #ea9999;} 15.purpleCell { background-color: #b4a7d6;} 16.blackCell { background-color: #000000;} 17</style> 18 19<div id="tb-wrapper"> 20<div id="tb"> 21 22<!-- table of contents --> 23<h2>This lesson teaches you to</h2> 24<ol> 25 <li><a href="#Confirm">Confirm You Need Multiple APKs</a></li> 26 <li><a href="#ChartReqs">Chart Your Requirements</a></li> 27 <li><a href="#CreateLibrary">Put All Common Code and Resources in a Library Project.</a></li> 28 <li><a href="#CreateAPKs">Create New APK Projects</a></li> 29 <li><a href="#AdjustManifests">Adjust the Manifests</a></li> 30 <li><a href="#PreLaunch">Go Over Pre-launch Checklist</a></li> 31</ol> 32 33<!-- other docs (NOT javadocs) --> 34<h2>You should also read</h2> 35<ul> 36 <li><a href="http://developer.android.com/google/play/publishing/multiple-apks.html">Multiple APK 37Support</a></li> 38</ul> 39 40</div> 41</div> 42 43<p>When developing your Android application to take advantage of multiple APKs on Google Play, 44it’s important to adopt some good practices from the get-go, and prevent unnecessary headaches 45further into the development process. This lesson shows you how to create multiple APKs of your 46app, each covering a different class of screen size. You will also gain some tools necessary to 47make maintaining a multiple APK codebase as painless as possible.</p> 48 49 50<h2 id="Confirm">Confirm You Need Multiple APKs</h2> 51 52<p>When trying to create an application that works across the huge range of available Android 53devices, naturally you want your application look its best on each individual device. You want to 54take advantage of the space of large screens but still work on small ones, to use new Android API 55features or visual textures available on cutting edge devices but not abandon older ones. It may 56seem at the outset as though multiple APK support is the best solution, but this often isn’t the 57case. The <a href="{@docRoot}google/play/publishing/multiple-apks.html#ApiLevelOptions">Using 58Single APK Instead</a> section of the multiple APK guide includes some useful information on how to 59accomplish all of this with a single APK, including use of our <a 60href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">support library</a>, 61and links to resources throughout the Android Developer guide.</p> 62 63<p>If you can manage it, confining your application to a single APK has several advantages, 64including:</p> 65 66<ul> 67<li>Publishing and Testing are easier</li> 68<li>There’s only one codebase to maintain</li> 69<li>Your application can adapt to device configuration changes</li> 70<li>App restore across devices just works</li> 71<li>You don’t have to worry about market preference, behavior from "upgrades" from one APK to the 72next, or which APK goes with which class of devices</li> 73</ul> 74 75<p>The rest of this lesson assumes that you’ve researched the topic, studiously absorbed the 76material in the resources linked, and determined that multiple APKs are the right path for your 77application.</p> 78 79 80<h2 id="ChartReqs">Chart Your Requirements</h2> 81 82<p>Start off by creating a simple chart to quickly determine how many APKs you need, and what screen 83size(s) each APK covers. Fortunately, it’s easy to chart out your requirements quickly, easily, and 84have an easy reference for later. Let’s say you want to split your APKs across two dimensions, API 85and screen size. Create a table with a row and column for each possible pair of values, and color 86in some "blobs", each color representing one APK.</p> 87 88<table cellpadding="10" cellspacing="0" border="1"> 89 <tbody> 90 <tr> 91 <td></td> 92 <td>3</td> 93 <td>4</td> 94 <td>5</td> 95 <td>6</td> 96 <td>7</td> 97 <td>8</td> 98 <td>9</td> 99 <td>10</td> 100 <td>11</td> 101 <td>12</td> 102 <td>+</td> 103 </tr> 104 <tr> 105 <td>small</td> 106 <td class="blueCell"></td> 107 <td class="blueCell"></td> 108 <td class="blueCell"></td> 109 <td class="blueCell"></td> 110 <td class="blueCell"></td> 111 <td class="blueCell"></td> 112 <td class="blueCell"></td> 113 <td class="blueCell"></td> 114 <td class="purpleCell"></td> 115 <td class="purpleCell"></td> 116 <td class="purpleCell"></td> 117 </tr> 118 <tr> 119 <td>normal</td> 120 <td class="blueCell"></td> 121 <td class="blueCell"></td> 122 <td class="blueCell"></td> 123 <td class="blueCell"></td> 124 <td class="blueCell"></td> 125 <td class="blueCell"></td> 126 <td class="blueCell"></td> 127 <td class="blueCell"></td> 128 <td class="purpleCell"></td> 129 <td class="purpleCell"></td> 130 <td class="purpleCell"></td> 131 </tr> 132 <tr> 133 <td>large</td> 134 <td class="greenCell"></td> 135 <td class="greenCell"></td> 136 <td class="greenCell"></td> 137 <td class="greenCell"></td> 138 <td class="greenCell"></td> 139 <td class="greenCell"></td> 140 <td class="greenCell"></td> 141 <td class="greenCell"></td> 142 <td class="purpleCell"></td> 143 <td class="purpleCell"></td> 144 <td class="purpleCell"></td> 145 </tr> 146 <tr> 147 <td>xlarge</td> 148 <td class="redCell"></td> 149 <td class="redCell"></td> 150 <td class="redCell"></td> 151 <td class="redCell"></td> 152 <td class="redCell"></td> 153 <td class="redCell"></td> 154 <td class="redCell"></td> 155 <td class="redCell"></td> 156 <td class="purpleCell"></td> 157 <td class="purpleCell"></td> 158 <td class="purpleCell"></td> 159 </tr> 160 </tbody> 161</table> 162 163<p> 164Above is an example with four APKs. Blue is for all small/normal screen devices, Green is for large 165screen devices, and Red is for xlarge screen devices, all with an API range of 3-10. Purple is a 166special case, as it’s for all screen sizes, but only for API 11 and up. More importantly, just by 167glancing at this chart, you immediately know which APK covers any given API/screen-size combo. To 168boot, you also have swanky codenames for each one, since "Have we tested red on the ?" is a lot 169easier to ask your cubie than "Have we tested the 3-to-10 xlarge APK against the Xoom?" Print this 170chart out and hand it to every person working on your codebase. Life just got a lot easier.</p> 171 172<h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project.</h2> 173 174<p>Whether you’re modifying an existing Android application or starting one from scratch, this is 175the first thing that you should do to the codebase, and by the far the most important. Everything 176that goes into the library project only needs to be updated once (think language-localized strings, 177color themes, bugs fixed in shared code), which improves your development time and reduces the 178likelihood of mistakes that could have been easily avoided.</p> 179 180<p class="note"><strong>Note:</strong> While the implementation details of how to create and 181include library projects are beyond the scope of this lesson, you can get up to speed quickly on 182their creation at the following links:</p> 183<ul> 184<li><a 185href="{@docRoot}tools/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up 186a library project (Eclipse)</a></li> 187<li><a 188href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up 189a library project (Command line)</a></li> 190</ul> 191 192<p>If you’re converting an existing application to use multiple APK support, 193scour your codebase for every localized string file, list of values, theme 194colors, menu icons and layout that isn’t going to change across APKs, and put 195it all in the library project. Code that isn’t going to change much should 196also go in the library project. You’ll likely find yourself extending these 197classes to add a method or two from APK to APK.</p> 198 199<p>If, on the other hand, you’re creating the application from scratch, try as 200much as possible to write code in the library project <em>first</em>, then only move it down to an 201individual APK if necessary. This is much easier to manage in the long run than adding it to one, 202then another, then another, then months later trying to figure out whether this blob can be moved up 203to the library section without screwing anything up.</p> 204 205<h2 id="CreateAPKs">Create New APK Projects</h2> 206<p>There should be a separate Android project for each APK you’re going to release. For easy 207organization, place the library project and all related APK projects under the same parent folder. 208Also remember that each APK needs to have the same package name, although they don’t necessarily 209need to share the package name with the library. If you were to have 3 APKs following the scheme 210described earlier, your root directory might look like this:</p> 211 212<pre class="no-pretty-print classic"> 213alexlucas:~/code/multi-apks-root$ ls 214foo-blue 215foo-green 216foo-lib 217foo-purple 218foo-red 219</pre> 220 221<p>Once the projects are created, add the library project as a reference to each APK project. If 222possible, define your starting Activity in the library project, and extend that Activity in your APK 223project. Having a starting activity defined in the library project gives you a chance to put all 224your application initialization in one place, so that each individual APK doesn’t have to 225re-implement "universal" tasks like initializing Analytics, running licensing checks, and any other 226initialization procedures that don’t change much from APK to APK.</p> 227 228 229<h2 id="AdjustManifests">Adjust the Manifests</h2> 230<p>When a user downloads an application which uses multiple APKs through Google Play, the correct 231APK to use is chosen using two simple rules: 232 233<ul> 234<li>The manifest has to show that particular APK is eligible</li> 235<li>Of the eligible APKs, highest version number wins.</li> 236</ul> 237 238<p>By way of example, let’s take the set of multiple APKs described earlier, and assume that each 239APK has been set to support all screen sizes larger than its "target" screen size. Let’s look at 240the sample chart from earlier:</p> 241 242<table cellpadding="10" cellspacing="0" border="1"> 243 <tbody> 244 <tr> 245 <td></td> 246 <td>3</td> 247 <td>4</td> 248 <td>5</td> 249 <td>6</td> 250 <td>7</td> 251 <td>8</td> 252 <td>9</td> 253 <td>10</td> 254 <td>11</td> 255 <td>12</td> 256 <td>+</td> 257 </tr> 258 <tr> 259 <td>small</td> 260 <td class="blueCell"></td> 261 <td class="blueCell"></td> 262 <td class="blueCell"></td> 263 <td class="blueCell"></td> 264 <td class="blueCell"></td> 265 <td class="blueCell"></td> 266 <td class="blueCell"></td> 267 <td class="blueCell"></td> 268 <td class="purpleCell"></td> 269 <td class="purpleCell"></td> 270 <td class="purpleCell"></td> 271 </tr> 272 <tr> 273 <td>normal</td> 274 <td class="blueCell"></td> 275 <td class="blueCell"></td> 276 <td class="blueCell"></td> 277 <td class="blueCell"></td> 278 <td class="blueCell"></td> 279 <td class="blueCell"></td> 280 <td class="blueCell"></td> 281 <td class="blueCell"></td> 282 <td class="purpleCell"></td> 283 <td class="purpleCell"></td> 284 <td class="purpleCell"></td> 285 </tr> 286 <tr> 287 <td>large</td> 288 <td class="greenCell"></td> 289 <td class="greenCell"></td> 290 <td class="greenCell"></td> 291 <td class="greenCell"></td> 292 <td class="greenCell"></td> 293 <td class="greenCell"></td> 294 <td class="greenCell"></td> 295 <td class="greenCell"></td> 296 <td class="purpleCell"></td> 297 <td class="purpleCell"></td> 298 <td class="purpleCell"></td> 299 </tr> 300 <tr> 301 <td>xlarge</td> 302 <td class="redCell"></td> 303 <td class="redCell"></td> 304 <td class="redCell"></td> 305 <td class="redCell"></td> 306 <td class="redCell"></td> 307 <td class="redCell"></td> 308 <td class="redCell"></td> 309 <td class="redCell"></td> 310 <td class="purpleCell"></td> 311 <td class="purpleCell"></td> 312 <td class="purpleCell"></td> 313 </tr> 314 </tbody> 315</table> 316<p>Since it’s okay for coverage to overlap, we can describe the area covered by each APK like 317so:</p> 318<ul> 319<li>Blue covers all screens, minSDK 3.</li> 320<li>Green covers Large screens and higher, minSDK 3.</li> 321<li>Red covers XLarge screens (generally tablets), minSDK of 9.</li> 322<li>Purple covers all screens, minSDK of 11.</li> 323</ul> 324<p>Note that there’s a <em>lot</em> of overlap in those rules. For instance, an 325XLarge device with API 11 can conceivably run any one of the 4 APKs specified. 326However, by using the "highest version number wins" rule, we can set an order of 327preference as follows:</p> 328<p> 329Purple ≥ Red ≥ Green ≥ Blue 330</p><p> 331Why allow all the overlap? Let’s pretend that the Purple APK has some requirement on it that the 332other two don’t. The <a href="{@docRoot}google/play/filters.html">Filters on Google Play</a> page 333of the Android Developer guide has a whole list of possible culprits. For the sake of example, 334let’s assume that Purple requires a front-facing camera. In fact, the entire point of Purple is to 335use entertaining things with the front-facing camera! But, it turns out, not all API 11+ devices 336even HAVE front-facing cameras! The horror!</p> 337 338<p>Fortunately, if a user is browsing Google Play from one such device, Google Play will look at the 339manifest, see that Purple lists the front-facing camera as a requirement, and quietly ignore it, 340having determined that Purple and that device are not a match made in digital heaven. It will then 341see that Red is not only compatible with xlarge devices, but also doesn’t care whether or not 342there’s a front-facing camera! The app can still be downloaded from Google Play by the user, 343because despite the whole front-camera mishap, there was still an APK that supported that particular 344API level.</p> 345 346<p> In order to keep all your APKs on separate "tracks", it’s important to have a good version code 347scheme. The recommended one can be found on the <a 348href="{@docRoot}google/play/publishing/multiple-apks.html#VersionCodes">Version Codes</a> area of 349our developer guide. It’s worth reading the whole section, but the basic gist is for this set of 350APKs, we’d use two digits to represent the minSDK, two to represent the min/max screen size, and 3 351to represent the build number. That way, when the device upgraded to a new version of Android, 352(say, from 10 to 11), any APKs that are now eligible and preferred over the currently installed one 353would be seen by the device as an "upgrade". The version number scheme, when applied to the example 354set of APKs, might look like:</p> 355 356<p>Blue: 0304001, 0304002, 0304003...<br /> 357Green: 0334001, 0334002, 0334003<br /> 358Red: 0344001, 0344002, 0344003...<br /> 359Purple: 1104001, 1104002, 1104003...<br /> 360</p> 361 362<p> Putting this all together, your Android Manifests would likely look something like the 363following:</p> 364<p>Blue:</p> 365<pre> 366<manifest xmlns:android="http://schemas.android.com/apk/res/android" 367 android:versionCode="0304001" android:versionName="1.0" package="com.example.foo"> 368 <uses-sdk android:minSdkVersion="3" /> 369 <supports-screens android:smallScreens="true" 370 android:normalScreens="true" 371 android:largeScreens="true" 372 android:xlargeScreens="true" /> 373 ... 374</pre> 375 376<p>Green:</p> 377<pre> 378<manifest xmlns:android="http://schemas.android.com/apk/res/android" 379 android:versionCode="0334001" android:versionName="1.0" package="com.example.foo"> 380 <uses-sdk android:minSdkVersion="3" /> 381 <supports-screens android:smallScreens="false" 382 android:normalScreens="false" 383 android:largeScreens="true" 384 android:xlargeScreens="true" /> 385 ... 386</pre> 387 388<p>Red:</p> 389<pre> 390<manifest xmlns:android="http://schemas.android.com/apk/res/android" 391 android:versionCode="0344001" android:versionName="1.0" package="com.example.foo"> 392 <uses-sdk android:minSdkVersion="3" /> 393 <supports-screens android:smallScreens="false" 394 android:normalScreens="false" 395 android:largeScreens="false" 396 android:xlargeScreens="true" /> 397 ... 398</pre> 399 400<p>Purple:</p> 401<pre> 402<manifest xmlns:android="http://schemas.android.com/apk/res/android" 403 android:versionCode="1104001" android:versionName="1.0" package="com.example.foo"> 404 <uses-sdk android:minSdkVersion="11" /> 405 <supports-screens android:smallScreens="true" 406 android:normalScreens="true" 407 android:largeScreens="true" 408 android:xlargeScreens="true" /> 409 ... 410</pre> 411 412<p> 413Note that technically, multiple APK’s will work with either the supports-screens tag, or the 414compatible-screens tag. Supports-screens is generally preferred, and it’s generally a really bad 415idea to use both- It makes things needlessly complicated, and increases the opportunity for errors. 416 Also note that instead of taking advantage of the default values (small and normal are always true 417by default), the manifests explicitly set the value for each screen size. This can save you 418headaches down the line - By way of example, a manifest with a target SDK of < 9 will have xlarge 419automatically set to false, since that size didn’t exist yet. So be explicit! 420</p> 421 422<h2 id="PreLaunch">Go Over Pre-launch Checklist</h2> 423<p> Before uploading to Google Play, double-check the following items. Remember that these are 424specifically relevant to multiple APKs, and in no way represent a complete checklist for all 425applications being uploaded to Google Play.</p> 426<ul> 427<li>All APKs must have the same package name.</li> 428<li>All APKs must be signed with the same certificate.</li> 429<li>If the APKs overlap in platform version, the one with the higher minSdkVersion must have a 430higher version code.</li> 431<li>Every screen size you want your APK to support, set to true in the manifest. Every screen size 432you want it to avoid, set to false.</li> 433<li>Double check your manifest filters for conflicting information (an APK that only supports 434cupcake on XLARGE screens isn’t going to be seen by anybody)</li> 435<li>Each APK's manifest must be unique across at least one of supported screen, OpenGL texture, or 436platform version.</li> 437<li>Try to test each APK on at least one device. Barring that, you have one of the most 438customizable device emulators in the business sitting on your development machine. Go nuts!</li> 439</ul> 440 441<p>It’s also worth inspecting the compiled APK before pushing to market, to make sure there aren’t 442any surprises that could hide your application on Google Play. This is actually quite simple using the 443"aapt" tool. Aapt (the Android Asset Packaging Tool) is part of the build process for creating and 444packaging your Android applications, and is also a very handy tool for inspecting them. </p> 445 446<pre class="no-pretty-print classic"> 447>aapt dump badging 448package: name='com.example.hello' versionCode='1' versionName='1.0' 449sdkVersion:'11' 450uses-permission:'android.permission.SEND_SMS' 451application-label:'Hello' 452application-icon-120:'res/drawable-ldpi/icon.png' 453application-icon-160:'res/drawable-mdpi/icon.png' 454application-icon-240:'res/drawable-hdpi/icon.png' 455application: label='Hello' icon='res/drawable-mdpi/icon.png' 456launchable-activity: name='com.example.hello.HelloActivity' label='Hello' icon='' 457uses-feature:'android.hardware.telephony' 458uses-feature:'android.hardware.touchscreen' 459main 460supports-screens: 'xlarge' 461supports-any-density: 'true' 462locales: '--_--' 463densities: '120' '160' '240' 464</pre> 465 466<p>When you examine aapt output, be sure to check that you don’t have conflicting values for 467supports-screens and compatible-screens, and that you don’t have unintended "uses-feature" values 468that were added as a result of permissions you set in the manifest. In the example above, the APK 469will be invisible to most, if not all devices.</p> 470<p>Why? By adding the required permission SEND_SMS, the feature requirement of android.hardware.telephony was implicitly added. Since most (if not all) xlarge devices are tablets without telephony hardware in them, Google Play will filter out this APK in these cases, until future devices come along which are both large enough to report as xlarge screen size, and possess telephony hardware. 471</p> 472<p>Fortunately this is easily fixed by adding the following to your manifest:<p> 473<pre> 474<uses-feature android:name="android.hardware.telephony" android:required="false" /> 475</pre> 476<p>The <code>android.hardware.touchscreen</code> requirement is also implicitly added. If you want your APK to be visible on TVs which are non-touchscreen devices you should add the following to your manifest:</p> 477<pre> 478<uses-feature android:name="android.hardware.touchscreen" android:required="false" /> 479</pre> 480 481<p>Once you’ve completed the pre-launch checklist, upload your APKs to Google Play. It may take a bit for the application to show up when browsing Google Play, but when it does, perform one last check. Download the application onto any test devices you may have to make sure that the APKs are targeting the intended devices. Congratulations, you’re done!</p> 482