Home | History | Annotate | Download | only in multiple-apks
      1 page.title=Creating Multiple APKs for Different Screen Sizes
      2 parent.title=Maintaining Multiple APKs
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 previous.title=Creating Multiple APKs for Different API Levels
      7 previous.link=api.html
      8 next.title=Creating Multiple APKs for Different GL Textures
      9 next.link=texture.html
     10 
     11 @jd:body
     12 
     13 <style type="text/css">
     14 .blueCell { background-color: #9fc5e8;}
     15 .greenCell { background-color: #b6d7a8;}
     16 .redCell { background-color: #ea9999;}
     17 .blackCell { background-color: #000000;}
     18 </style>
     19 
     20 <div id="tb-wrapper">
     21 <div id="tb">
     22 
     23 <!-- table of contents -->
     24 <h2>This lesson teaches you to</h2>
     25 <ol>
     26   <li><a href="#Confirm">Confirm You Need Multiple APKs</a></li>
     27   <li><a href="#ChartReqs">Chart Your Requirements</a></li>
     28   <li><a href="#CreateLibrary">Put All Common Code and Resources in a Library Project.</a></li>
     29   <li><a href="#CreateAPKs">Create New APK Projects</a></li>
     30   <li><a href="#AdjustManifests">Adjust the Manifests</a></li>
     31   <li><a href="#PreLaunch">Go Over Pre-launch Checklist</a></li>
     32 </ol>
     33 
     34 <!-- other docs (NOT javadocs) -->
     35 <h2>You should also read</h2>
     36 <ul>
     37   <li><a href="http://developer.android.com/google/play/publishing/multiple-apks.html">Multiple APK
     38 Support</a></li>
     39   <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
     40 </ul>
     41 
     42 </div>
     43 </div>
     44 
     45 
     46 <p>When developing your Android application to take advantage of multiple APKs on Google Play,
     47 its important to adopt some good practices from the get-go, and prevent unnecessary headaches
     48 further into the development process.  This lesson shows you how to create multiple APKs of your
     49 app, each covering a different class of screen size.  You will also gain some tools necessary to
     50 make maintaining a multiple APK codebase as painless as possible.</p>
     51 
     52 
     53 <h2 id="Confirm">Confirm You Need Multiple APKs</h2>
     54 
     55 <p>When trying to create an application that works across multiple sizes of Android devices,
     56 naturally you want your application to take advantage of all the available space on larger devices,
     57 without sacrificing compatibility or usability on the smaller screens.  It may seem at the outset as
     58 though multiple APK support is the best solution, but this often isnt the case.  The <a
     59 href="{@docRoot}google/play/publishing/multiple-apks.html#ApiLevelOptions">Using Single APK
     60 Instead</a> section of the multiple APK developer guide includes some useful information on how to
     61 accomplish this with a single APK, including use of our support library. You should also read the 
     62 guide to <a href="{@docRoot}guide/practices/screens_support.html">supporting multiple screens</a>,
     63 and theres even a <a
     64 href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">support library</a> you
     65 can download using the Android SDK, which lets you use fragments on pre-Honeycomb devices (making
     66 multiple-screen support in a single APK much easier).</p>
     67 
     68 <p>If you can manage it, confining your application to a single APK has several advantages,
     69 including:</p>
     70 
     71 <ul>
     72 <li>Publishing and testing are easier</li>
     73 <li>Theres only one codebase to maintain</li>
     74 <li>Your application can adapt to device configuration changes</li>
     75 <li>App restore across devices just works</li>
     76 <li>You dont have to worry about market preference, behavior from "upgrades" from one APK to the
     77 next, or which APK goes with which class of devices</li>
     78 </ul>
     79 
     80 <p>The rest of this lesson assumes that youve researched the topic, studiously absorbed the
     81 material in the resources linked, and determined that multiple APKs are the right path for your
     82 application.</p>
     83 
     84 <h2 id="ChartReqs">Chart Your Requirements</h2>
     85 
     86 <p>Start off by creating a simple chart to quickly determine how many APKs you need, and what screen
     87 size(s) each APK covers.  Fortunately, its easy to chart out your requirements quickly and easily,
     88 and have a reference for later.  Start out with a row of cells representing the various screen sizes
     89 available on the Android platform.</p>
     90 
     91 <table cellpadding="10" cellspacing="0" border="1">
     92   <tbody>
     93     <tr>
     94       <td>small</td>
     95       <td>normal</td>
     96       <td>large</td>
     97       <td>xlarge</td>
     98     </tr>
     99   </tbody>
    100 </table>
    101 <p>
    102 Now just color in the chart such that each color represents an APK.  Heres one example of how you
    103 might apply each APK to a certain range of screen sizes.</p>
    104 
    105 <table cellpadding="10" cellspacing="0" border="1">
    106   <tbody>
    107     <tr>
    108       <td class="blueCell">small</td>
    109       <td class="blueCell">normal</td>
    110       <td class="greenCell">large</td>
    111       <td class="redCell">xlarge</td>
    112     </tr>
    113   </tbody>
    114 </table>
    115 <p>
    116 Depending on your needs, you could also have two APKs, "small and everything else" or "xlarge and
    117 everything else".  Coloring in the chart also makes intra-team communication easier&mdash;You can
    118 now simply refer to each APK as "blue", "green", or "red", no matter how many different screen types
    119 it covers.</p>
    120 
    121 <h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project.</h2>
    122 <p>Whether youre modifying an existing Android application or starting one from scratch, this is
    123 the first thing that you should do to the codebase, and by the far the most important.  Everything
    124 that goes into the library project only needs to be updated once (think language-localized strings,
    125 color themes, bugs fixed in shared code), which improves your development time and reduces the
    126 likelihood of mistakes that could have been easily avoided.</p>
    127 
    128 <p class="note"><strong>Note:</strong>  While the implementation details of how to create and
    129 include library projects are beyond the scope of this lesson, you can get up to speed quickly on
    130 their creation at the following links:</p>
    131 <ul>
    132 <li><a
    133 href="{@docRoot}tools/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up
    134 a library project (Eclipse)</a></li>
    135 <li><a
    136 href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up
    137 a library project (Command line)</a></li>
    138 </ul>
    139 
    140 
    141 
    142 <p>If youre converting an existing application to use multiple APK support,
    143 scour your codebase for every localized string file, list of values, theme
    144 colors, menu icons and layout that isnt going to change across APKs, and put
    145 it all in the library project.  Code that isnt going to change much should
    146 also go in the library project.  Youll likely find yourself extending these
    147 classes to add a method or two from APK to APK.</p>
    148 
    149 <p>If, on the other hand, youre creating the application from scratch, try as
    150 much as possible to write code in the library project <em>first</em>, then only move it down to an
    151 individual APK if necessary.  This is much easier to manage in the long run than adding it to one,
    152 then another, then another, then months later trying to figure out whether this blob can be moved up
    153 to the library section without screwing anything up.</p>
    154 
    155 
    156 
    157 <h2 id="CreateAPKs">Create New APK Projects</h2>
    158 <p>There should be a separate Android project for each APK youre going to release.  For easy
    159 organization, place the library project and all related APK projects under the same parent folder. 
    160 Also remember that each APK needs to have the same package name, although they dont necessarily
    161 need to share the package name with the library.  If you were to have 3 APKs following the scheme
    162 described earlier, your root directory might look like this:</p>
    163 
    164 <pre class="no-pretty-print classic">
    165 alexlucas:~/code/multi-apks-root$ ls
    166 foo-blue
    167 foo-green
    168 foo-lib
    169 foo-red
    170 </pre>
    171 
    172 <p>Once the projects are created, add the library project as a reference to each APK project.  If
    173 possible, define your starting Activity in the library project, and extend that Activity in your APK
    174 project.  Having a starting activity defined in the library project gives you a chance to put all
    175 your application initialization in one place, so that each individual APK doesnt have to
    176 re-implement "universal" tasks like initializing Analytics, running licensing checks, and any other
    177 initialization procedures that dont change much from APK to APK.</p>
    178 
    179 
    180 <h2 id="AdjustManifests">Adjust the Manifests</h2>
    181 <p>When a user downloads an application which uses multiple APKs through Google Play, the correct
    182 APK to use is chosen using two simple rules:</p>
    183 <ul>
    184 <li>The manifest has to show that particular APK is eligible</li>
    185 <li>Of the eligible APKs, highest version number wins</li>
    186 </ul>
    187 
    188 <p>
    189 By way of example, lets take the set of multiple APKs described earlier, and assume that each APK
    190 has been set to support all screen sizes larger than its "target" screen size.  Taken individually,
    191 the possible range of each APK would look like this:
    192 </p>
    193 <table cellpadding="10" cellspacing="0" border="1">
    194   <tbody>
    195     <tr>
    196       <td class="blueCell">small</td>
    197       <td class="blueCell">normal</td>
    198       <td class="blueCell">large</td>
    199       <td class="blueCell">xlarge</td>
    200     </tr>
    201     <tr>
    202       <td class="blackCell">small</td>
    203       <td class="blackCell">normal</td>
    204       <td class="greenCell">large</td>
    205       <td class="greenCell">xlarge</td>
    206     </tr>
    207     <tr>
    208       <td class="blackCell">small</td>
    209       <td class="blackCell">normal</td>
    210       <td class="blackCell">large</td>
    211       <td class="redCell">xlarge</td>
    212     </tr>
    213   </tbody>
    214 </table>
    215 <p>
    216 However, by using the "highest version number wins" rule, if we set the versionCode attribute in
    217 each APK such that red &#8805; green &#8805; blue, the chart effectively collapses down to this:</p>
    218 <table cellpadding="10" cellspacing="0" border="1">
    219   <tbody>
    220     <tr>
    221       <td class="blueCell">small</td>
    222       <td class="blueCell">normal</td>
    223       <td class="greenCell">large</td>
    224       <td class="redCell">xlarge</td>
    225     </tr>
    226   </tbody>
    227 </table>
    228 <p>
    229 Now, lets further assume that the Red APK has some requirement on it that the other two dont.  The
    230 <a href="{@docRoot}google/play/filters.html">Filters on Google Play</a> page of the Android
    231 Developer guide has a whole list of possible culprits.  For the sake of example, lets assume that
    232 red requires a front-facing camera.  In fact, the entire point of the red APK is to use the extra
    233 available screen space to do entertaining things with that front-facing camera.  But, it turns out,
    234 not all xlarge devices even HAVE front-facing cameras!  The horror!</p>
    235 
    236 <p>Fortunately, if a user is browsing Google Play from one such device, Google Play will look at the
    237 manifest, see that Red lists the front-facing camera as a requirement, and quietly ignore it, having
    238 determined that Red and that device are not a match made in digital heaven.  It will then see that
    239 Green is not only compatible with xlarge devices, but also doesnt care whether or not theres a
    240 front-facing camera!  The app can still be downloaded from Google Play by the user, because
    241 despite the whole front-camera mishap, there was still an APK that supported that particular screen
    242 size.</p>
    243 
    244 <p>  In order to keep all your APKs on separate "tracks", its important to have a good version code
    245 scheme.  The recommended one can be found on the <a
    246 href="{@docRoot}google/play/publishing/multiple-apks.html#VersionCodes">Version Codes</a> area of
    247 our developer guide.  Since the example set of APKs is only dealing with one of 3 possible
    248 dimensions, it would be sufficient to separate each APK by 1000 and increment from there.  This
    249 might look like:</p>
    250 
    251 <p>Blue: 1001, 1002, 1003, 1004...<br />
    252 Green: 2001, 2002, 2003, 2004...<br />
    253 Red:3001, 3002, 3003, 3004...</p>
    254 
    255 <p>  Putting this all together, your Android Manifests would likely look something like the
    256 following:</p>
    257 
    258 <p>Blue:</p>
    259 <pre>
    260 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    261     android:versionCode="1001" android:versionName="1.0" package="com.example.foo"&gt;
    262     &lt;supports-screens android:smallScreens="true"
    263         android:normalScreens="true"
    264         android:largeScreens="true"
    265         android:xlargeScreens="true" /&gt;
    266     ...
    267 </pre>
    268 
    269 <p>Green:</p>
    270 <pre>
    271 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    272     android:versionCode="2001" android:versionName="1.0" package="com.example.foo">
    273     &lt;supports-screens android:smallScreens="false"
    274         android:normalScreens="false"
    275         android:largeScreens="true"
    276         android:xlargeScreens="true" />
    277     ...
    278 </pre>
    279 
    280 <p>Red:</p>
    281 <pre>
    282 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    283     android:versionCode="3001" android:versionName="1.0" package="com.example.foo"&gt;
    284     &lt;supports-screens android:smallScreens="false"
    285         android:normalScreens="false"
    286         android:largeScreens="false"
    287         android:xlargeScreens="true" /&gt;
    288     ...
    289 </pre>
    290 <p>
    291 Note that technically, multiple APKs will work with either the supports-screens
    292 tag, or the compatible-screens tag.  Supports-screens is generally preferred,
    293 and its generally a really bad idea to use both tags in the same manifest.  It
    294 makes things needlessly complicated, and increases the opportunity for errors.
    295 Also note that instead of taking advantage of the default values (small and
    296 normal are always true by default), the manifests explicitly set the value for
    297 each screen size.  This can save you headaches down the line.  For instance, a manifest with a
    298 target SDK of &lt; 9 will have xlarge automatically set to false, since that size didnt exist yet. 
    299 So be explicit!
    300 </p>
    301 
    302 <h2 id="PreLaunch">Go Over Pre-launch Checklist</h2>
    303 <p>  Before uploading to Google Play, double-check the following items.  Remember that these are
    304 specifically relevant to multiple APKs, and in no way represent a complete checklist for all
    305 applications being uploaded to Google Play.</p>
    306 <ul>
    307 <li>All APKs must have the same package name</li>
    308 <li>All APKs must be signed with the same certificate</li>
    309 <li>Every screen size you want your APK to support, set to true in the manifest.  Every screen size
    310 you want it to avoid, set to false</li>
    311 <li>Double check your manifest filters for conflicting information (an APK that only supports
    312 cupcake on XLARGE screens isnt going to be seen by anybody)</li>
    313 <li>Each APK's manifest must be unique across at least one of supported screen, openGL texture, or
    314 platform version</li>
    315 <li>Try to test each APK on at least one device.  Barring that, you have one of the most
    316 customizable device emulators in the business sitting on your development machine.  Go nuts!</li>
    317 </ul>
    318 
    319 <p>Its also worth inspecting the compiled APK before pushing to market, to make sure there arent
    320 any surprises that could hide your application on Google Play.  This is actually quite simple using the
    321 "aapt" tool.  Aapt (the Android Asset Packaging Tool) is part of the build process for creating and
    322 packaging your Android applications, and is also a very handy tool for inspecting them. </p>
    323 
    324 <pre class="no-pretty-print classic">
    325 &gt;aapt dump badging
    326 package: name='com.example.hello' versionCode='1' versionName='1.0'
    327 sdkVersion:'11'
    328 uses-permission:'android.permission.SEND_SMS'
    329 application-label:'Hello'
    330 application-icon-120:'res/drawable-ldpi/icon.png'
    331 application-icon-160:'res/drawable-mdpi/icon.png'
    332 application-icon-240:'res/drawable-hdpi/icon.png'
    333 application: label='Hello' icon='res/drawable-mdpi/icon.png'
    334 launchable-activity: name='com.example.hello.HelloActivity'  label='Hello' icon=''
    335 uses-feature:'android.hardware.telephony'
    336 uses-feature:'android.hardware.touchscreen'
    337 main
    338 supports-screens: 'xlarge'
    339 supports-any-density: 'true'
    340 locales: '--_--'
    341 densities: '120' '160' '240'
    342 </pre>
    343 
    344 <p>When you examine aapt output, be sure to check that you dont have conflicting values for
    345 supports-screens and compatible-screens, and that you dont have unintended "uses-feature" values
    346 that were added as a result of permissions you set in the manifest. In the example above, the APK
    347 will be invisible to most, if not all devices.</p>
    348 <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.
    349 </p>
    350 <p>Fortunately this is easily fixed by adding the following to your
    351 manifest:</p>
    352 <pre>
    353 &lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;
    354 </pre>
    355 <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>
    356 <pre>
    357 &lt;uses-feature android:name="android.hardware.touchscreen" android:required="false" /&gt;
    358 </pre>
    359 
    360 <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>
    361