Home | History | Annotate | Download | only in multiple-apks
      1 page.title=Creating Multiple APKs with 2+ Dimensions
      2 parent.title=Maintaining Multiple APKs
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 previous.title=Creating Multiple APKs for Different GL Textures
      7 previous.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
     37 Support</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,
     44 its important to adopt some good practices from the get-go, and prevent unnecessary headaches
     45 further into the development process.  This lesson shows you how to create multiple APKs of your
     46 app, each covering a different class of screen size.  You will also gain some tools necessary to
     47 make 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
     53 devices, naturally you want your application look its best on each individual device.  You want to
     54 take advantage of the space of large screens but still work on small ones, to use new Android API
     55 features or visual textures available on cutting edge devices but not abandon older ones.  It may
     56 seem at the outset as though multiple APK support is the best solution, but this often isnt the
     57 case.  The <a href="{@docRoot}google/play/publishing/multiple-apks.html#ApiLevelOptions">Using
     58 Single APK Instead</a> section of the multiple APK guide includes some useful information on how to
     59 accomplish all of this with a single APK, including use of our <a
     60 href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">support library</a>,
     61 and 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,
     64 including:</p>
     65 
     66 <ul>
     67 <li>Publishing and Testing are easier</li>
     68 <li>Theres 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 dont have to worry about market preference, behavior from "upgrades" from one APK to the
     72 next, or which APK goes with which class of devices</li>
     73 </ul>
     74 
     75 <p>The rest of this lesson assumes that youve researched the topic, studiously absorbed the
     76 material in the resources linked, and determined that multiple APKs are the right path for your
     77 application.</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
     83 size(s) each APK covers.  Fortunately, its easy to chart out your requirements quickly, easily, and
     84 have an easy reference for later.  Lets say you want to split your APKs across two dimensions, API
     85 and screen size.  Create a table with a row and column for each possible pair of values, and color
     86 in 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>
    164 Above is an example with four APKs. Blue is for all small/normal screen devices, Green is for large
    165 screen devices, and Red is for xlarge screen devices, all with an API range of 3-10.  Purple is a
    166 special case, as its for all screen sizes, but only for API 11 and up.  More importantly, just by
    167 glancing at this chart, you immediately know which APK covers any given API/screen-size combo.  To
    168 boot, you also have swanky codenames for each one, since "Have we tested red on the ?" is a lot
    169 easier to ask your cubie than "Have we tested  the 3-to-10 xlarge APK against the Xoom?"  Print this
    170 chart 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 youre modifying an existing Android application or starting one from scratch, this is
    175 the first thing that you should do to the codebase, and by the far the most important.  Everything
    176 that goes into the library project only needs to be updated once (think language-localized strings,
    177 color themes, bugs fixed in shared code), which improves your development time and reduces the
    178 likelihood 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
    181 include library projects are beyond the scope of this lesson, you can get up to speed
    182 by reading <a
    183 href="{@docRoot}studio/projects/android-library.html">Create an Android Library</a>.</p>
    184 
    185 <p>If youre converting an existing application to use multiple APK support,
    186 scour your codebase for every localized string file, list of values, theme
    187 colors, menu icons and layout that isnt going to change across APKs, and put
    188 it all in the library project.  Code that isnt going to change much should
    189 also go in the library project.  Youll likely find yourself extending these
    190 classes to add a method or two from APK to APK.</p>
    191 
    192 <p>If, on the other hand, youre creating the application from scratch, try as
    193 much as possible to write code in the library project <em>first</em>, then only move it down to an
    194 individual APK if necessary.  This is much easier to manage in the long run than adding it to one,
    195 then another, then another, then months later trying to figure out whether this blob can be moved up
    196 to the library section without screwing anything up.</p>
    197 
    198 <h2 id="CreateAPKs">Create New APK Projects</h2>
    199 <p>There should be a separate Android project for each APK youre going to release.  For easy
    200 organization, place the library project and all related APK projects under the same parent folder.
    201 Also remember that each APK needs to have the same package name, although they dont necessarily
    202 need to share the package name with the library.  If you were to have 3 APKs following the scheme
    203 described earlier, your root directory might look like this:</p>
    204 
    205 <pre class="no-pretty-print classic">
    206 alexlucas:~/code/multi-apks-root$ ls
    207 foo-blue
    208 foo-green
    209 foo-lib
    210 foo-purple
    211 foo-red
    212 </pre>
    213 
    214 <p>Once the projects are created, add the library project as a reference to each APK project.  If
    215 possible, define your starting Activity in the library project, and extend that Activity in your APK
    216 project.  Having a starting activity defined in the library project gives you a chance to put all
    217 your application initialization in one place, so that each individual APK doesnt have to
    218 re-implement "universal" tasks like initializing Analytics, running licensing checks, and any other
    219 initialization procedures that dont change much from APK to APK.</p>
    220 
    221 
    222 <h2 id="AdjustManifests">Adjust the Manifests</h2>
    223 <p>When a user downloads an application which uses multiple APKs through Google Play, the correct
    224 APK to use is chosen using two simple rules:
    225 
    226 <ul>
    227 <li>The manifest has to show that particular APK is eligible</li>
    228 <li>Of the eligible APKs, highest version number wins.</li>
    229 </ul>
    230 
    231 <p>By way of example, lets take the set of multiple APKs described earlier, and assume that each
    232 APK has been set to support all screen sizes larger than its "target" screen size.  Lets look at
    233 the sample chart from earlier:</p>
    234 
    235 <table cellpadding="10" cellspacing="0" border="1">
    236   <tbody>
    237     <tr>
    238       <td></td>
    239       <td>3</td>
    240       <td>4</td>
    241       <td>5</td>
    242       <td>6</td>
    243       <td>7</td>
    244       <td>8</td>
    245       <td>9</td>
    246       <td>10</td>
    247       <td>11</td>
    248       <td>12</td>
    249       <td>+</td>
    250     </tr>
    251     <tr>
    252       <td>small</td>
    253       <td class="blueCell"></td>
    254       <td class="blueCell"></td>
    255       <td class="blueCell"></td>
    256       <td class="blueCell"></td>
    257       <td class="blueCell"></td>
    258       <td class="blueCell"></td>
    259       <td class="blueCell"></td>
    260       <td class="blueCell"></td>
    261       <td class="purpleCell"></td>
    262       <td class="purpleCell"></td>
    263       <td class="purpleCell"></td>
    264     </tr>
    265     <tr>
    266       <td>normal</td>
    267       <td class="blueCell"></td>
    268       <td class="blueCell"></td>
    269       <td class="blueCell"></td>
    270       <td class="blueCell"></td>
    271       <td class="blueCell"></td>
    272       <td class="blueCell"></td>
    273       <td class="blueCell"></td>
    274       <td class="blueCell"></td>
    275       <td class="purpleCell"></td>
    276       <td class="purpleCell"></td>
    277       <td class="purpleCell"></td>
    278     </tr>
    279     <tr>
    280       <td>large</td>
    281       <td class="greenCell"></td>
    282       <td class="greenCell"></td>
    283       <td class="greenCell"></td>
    284       <td class="greenCell"></td>
    285       <td class="greenCell"></td>
    286       <td class="greenCell"></td>
    287       <td class="greenCell"></td>
    288       <td class="greenCell"></td>
    289       <td class="purpleCell"></td>
    290       <td class="purpleCell"></td>
    291       <td class="purpleCell"></td>
    292     </tr>
    293     <tr>
    294       <td>xlarge</td>
    295       <td class="redCell"></td>
    296       <td class="redCell"></td>
    297       <td class="redCell"></td>
    298       <td class="redCell"></td>
    299       <td class="redCell"></td>
    300       <td class="redCell"></td>
    301       <td class="redCell"></td>
    302       <td class="redCell"></td>
    303       <td class="purpleCell"></td>
    304       <td class="purpleCell"></td>
    305       <td class="purpleCell"></td>
    306     </tr>
    307   </tbody>
    308 </table>
    309 <p>Since its okay for coverage to overlap, we can describe the area covered by each APK like
    310 so:</p>
    311 <ul>
    312 <li>Blue covers all screens, minSDK 3.</li>
    313 <li>Green covers Large screens and higher, minSDK 3.</li>
    314 <li>Red covers XLarge screens (generally tablets), minSDK of 9.</li>
    315 <li>Purple covers all screens, minSDK of 11.</li>
    316 </ul>
    317 <p>Note that theres a <em>lot</em> of overlap in those rules.  For instance, an
    318 XLarge device with API 11 can conceivably run any one of the 4 APKs specified.
    319 However, by using the "highest version number wins" rule, we can set an order of
    320 preference as follows:</p>
    321 <p>
    322 Purple &#8805; Red &#8805; Green &#8805; Blue
    323 </p><p>
    324 Why allow all the overlap?  Lets pretend that the Purple APK has some requirement on it that the
    325 other two dont.  The <a href="{@docRoot}google/play/filters.html">Filters on Google Play</a> page
    326 of the Android Developer guide has a whole list of possible culprits.  For the sake of example,
    327 lets assume that Purple requires a front-facing camera.  In fact, the entire point of Purple is to
    328 use entertaining things with the front-facing camera!  But, it turns out, not all API 11+ devices
    329 even HAVE front-facing cameras!  The horror!</p>
    330 
    331 <p>Fortunately, if a user is browsing Google Play from one such device, Google Play will look at the
    332 manifest, see that Purple lists the front-facing camera as a requirement, and quietly ignore it,
    333 having determined that Purple and that device are not a match made in digital heaven.  It will then
    334 see that Red is not only compatible with xlarge devices, but also doesnt care whether or not
    335 theres a front-facing camera!  The app can still be downloaded from Google Play by the user,
    336 because despite the whole front-camera mishap, there was still an APK that supported that particular
    337 API level.</p>
    338 
    339 <p>  In order to keep all your APKs on separate "tracks", its important to have a good version code
    340 scheme.  The recommended one can be found on the <a
    341 href="{@docRoot}google/play/publishing/multiple-apks.html#VersionCodes">Version Codes</a> area of
    342 our developer guide.  Its worth reading the whole section, but the basic gist is for this set of
    343 APKs, wed use two digits to represent the minSDK, two to represent the min/max screen size, and 3
    344 to represent the build number.  That way, when the device upgraded to a new version of Android,
    345 (say, from 10 to 11), any APKs that are now eligible and preferred over the currently installed one
    346 would be seen by the device as an "upgrade".  The version number scheme, when applied to the example
    347 set of APKs, might look like:</p>
    348 
    349 <p>Blue: 0304001, 0304002, 0304003...<br />
    350 Green: 0334001, 0334002, 0334003<br />
    351 Red: 0344001, 0344002, 0344003...<br />
    352 Purple: 1104001, 1104002, 1104003...<br />
    353 </p>
    354 
    355 <p>  Putting this all together, your Android Manifests would likely look something like the
    356 following:</p>
    357 <p>Blue:</p>
    358 <pre>
    359 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    360     android:versionCode="0304001" android:versionName="1.0" package="com.example.foo"&gt;
    361     &lt;uses-sdk android:minSdkVersion="3" /&gt;
    362     &lt;supports-screens android:smallScreens="true"
    363         android:normalScreens="true"
    364         android:largeScreens="true"
    365         android:xlargeScreens="true" /&gt;
    366     ...
    367 </pre>
    368 
    369 <p>Green:</p>
    370 <pre>
    371 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    372     android:versionCode="0334001" android:versionName="1.0" package="com.example.foo"&gt;
    373     &lt;uses-sdk android:minSdkVersion="3" /&gt;
    374     &lt;supports-screens android:smallScreens="false"
    375         android:normalScreens="false"
    376         android:largeScreens="true"
    377         android:xlargeScreens="true" /&gt;
    378     ...
    379 </pre>
    380 
    381 <p>Red:</p>
    382 <pre>
    383 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    384     android:versionCode="0344001" android:versionName="1.0" package="com.example.foo"&gt;
    385     &lt;uses-sdk android:minSdkVersion="3" /&gt;
    386     &lt;supports-screens android:smallScreens="false"
    387         android:normalScreens="false"
    388         android:largeScreens="false"
    389         android:xlargeScreens="true" /&gt;
    390     ...
    391 </pre>
    392 
    393 <p>Purple:</p>
    394 <pre>
    395 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    396     android:versionCode="1104001" android:versionName="1.0" package="com.example.foo"&gt;
    397     &lt;uses-sdk android:minSdkVersion="11" /&gt;
    398     &lt;supports-screens android:smallScreens="true"
    399         android:normalScreens="true"
    400         android:largeScreens="true"
    401         android:xlargeScreens="true" /&gt;
    402     ...
    403 </pre>
    404 
    405 <p>
    406 Note that technically, multiple APKs will work with either the supports-screens tag, or the
    407 compatible-screens tag.  Supports-screens is generally preferred, and its generally a really bad
    408 idea to use both-  It makes things needlessly complicated, and increases the opportunity for errors.
    409  Also note that instead of taking advantage of the default values (small and normal are always true
    410 by default), the manifests explicitly set the value for each screen size.  This can save you
    411 headaches down the line - By way of example, a manifest with a target SDK of &lt; 9 will have xlarge
    412 automatically set to false, since that size didnt exist yet.  So be explicit!
    413 </p>
    414 
    415 <h2 id="PreLaunch">Go Over Pre-launch Checklist</h2>
    416 <p>  Before uploading to Google Play, double-check the following items.  Remember that these are
    417 specifically relevant to multiple APKs, and in no way represent a complete checklist for all
    418 applications being uploaded to Google Play.</p>
    419 <ul>
    420 <li>All APKs must have the same package name.</li>
    421 <li>All APKs must be signed with the same certificate.</li>
    422 <li>If the APKs overlap in platform version, the one with the higher minSdkVersion must have a
    423 higher version code.</li>
    424 <li>Every screen size you want your APK to support, set to true in the manifest.  Every screen size
    425 you want it to avoid, set to false.</li>
    426 <li>Double check your manifest filters for conflicting information (an APK that only supports
    427 cupcake on XLARGE screens isnt going to be seen by anybody)</li>
    428 <li>Each APK's manifest must be unique across at least one of supported screen, OpenGL texture, or
    429 platform version.</li>
    430 <li>Try to test each APK on at least one device.  Barring that, you have one of the most
    431 customizable device emulators in the business sitting on your development machine.  Go nuts!</li>
    432 </ul>
    433 
    434 <p>Its also worth inspecting the compiled APK before pushing to market, to make sure there arent
    435 any surprises that could hide your application on Google Play.  This is actually quite simple using the
    436 "aapt" tool.  Aapt (the Android Asset Packaging Tool) is part of the build process for creating and
    437 packaging your Android applications, and is also a very handy tool for inspecting them. </p>
    438 
    439 <pre class="no-pretty-print classic">
    440 &gt;aapt dump badging
    441 package: name='com.example.hello' versionCode='1' versionName='1.0'
    442 sdkVersion:'11'
    443 uses-permission:'android.permission.SEND_SMS'
    444 application-label:'Hello'
    445 application-icon-120:'res/drawable-ldpi/icon.png'
    446 application-icon-160:'res/drawable-mdpi/icon.png'
    447 application-icon-240:'res/drawable-hdpi/icon.png'
    448 application: label='Hello' icon='res/drawable-mdpi/icon.png'
    449 launchable-activity: name='com.example.hello.HelloActivity'  label='Hello' icon=''
    450 uses-feature:'android.hardware.telephony'
    451 uses-feature:'android.hardware.touchscreen'
    452 main
    453 supports-screens: 'xlarge'
    454 supports-any-density: 'true'
    455 locales: '--_--'
    456 densities: '120' '160' '240'
    457 </pre>
    458 
    459 <p>When you examine aapt output, be sure to check that you dont have conflicting values for
    460 supports-screens and compatible-screens, and that you dont have unintended "uses-feature" values
    461 that were added as a result of permissions you set in the manifest. In the example above, the APK
    462 will be invisible to most, if not all devices.</p>
    463 <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.
    464 </p>
    465 <p>Fortunately this is easily fixed by adding the following to your manifest:<p>
    466 <pre>
    467 &lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;
    468 </pre>
    469 <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>
    470 <pre>
    471 &lt;uses-feature android:name="android.hardware.touchscreen" android:required="false" /&gt;
    472 </pre>
    473 
    474 <p>Once youve 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, youre done!</p>
    475