screensize.jd revision 2c76efc5147e567eb64d255fb48fa490b02004b8
1page.title=Creating Multiple APKs for Different Screen Sizes
2parent.title=Creating and Maintaining Multiple APKs
3parent.link=index.html
4
5trainingnavtop=true
6previous.title=Creating Multiple APKs for Different API Levels
7previous.link=api.html
8next.title=Creating Multiple APKs for Different GL Textures
9next.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/guide/market/publishing/multiple-apks.html">Multiple APK
38Support</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 Android Market,
47it’s important to adopt some good practices from the get-go, and prevent unnecessary headaches
48further into the development process.  This lesson shows you how to create multiple APKs of your
49app, each covering a different class of screen size.  You will also gain some tools necessary to
50make 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,
56naturally you want your application to take advantage of all the available space on larger devices,
57without sacrificing compatibility or usability on the smaller screens.  It may seem at the outset as
58though multiple APK support is the best solution, but this often isn’t the case.  The <a
59href="{@docRoot}guide/market/publishing/multiple-apks.html#ApiLevelOptions">Using Single APK
60Instead</a> section of the multiple APK developer guide includes some useful information on how to
61accomplish this with a single APK, including use of our support library. You should also read the 
62guide to <a href="{@docRoot}guide/practices/screens_support.html">supporting multiple screens</a>,
63and there’s even a <a
64href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">support library</a> you
65can download using the Android SDK, which lets you use fragments on pre-Honeycomb devices (making
66multiple-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,
69including:</p>
70
71<ul>
72<li>Publishing and testing are easier</li>
73<li>There’s 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 don’t have to worry about market preference, behavior from "upgrades" from one APK to the
77next, or which APK goes with which class of devices</li>
78</ul>
79
80<p>The rest of this lesson assumes that you’ve researched the topic, studiously absorbed the
81material in the resources linked, and determined that multiple APKs are the right path for your
82application.</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
87size(s) each APK covers.  Fortunately, it’s easy to chart out your requirements quickly and easily,
88and have a reference for later.  Start out with a row of cells representing the various screen sizes
89available 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>
102Now just color in the chart such that each color represents an APK.  Here’s one example of how you
103might 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>
116Depending on your needs, you could also have two APKs, "small and everything else" or "xlarge and
117everything else".  Coloring in the chart also makes intra-team communication easier&mdash;You can
118now simply refer to each APK as "blue", "green", or "red", no matter how many different screen types
119it covers.</p>
120
121<h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project.</h2>
122<p>Whether you’re modifying an existing Android application or starting one from scratch, this is
123the first thing that you should do to the codebase, and by the far the most important.  Everything
124that goes into the library project only needs to be updated once (think language-localized strings,
125color themes, bugs fixed in shared code), which improves your development time and reduces the
126likelihood 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
129include library projects are beyond the scope of this lesson, you can get up to speed quickly on
130their creation at the following links:</p>
131<ul>
132<li><a
133href="{@docRoot}guide/developing/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up
134a library project (Eclipse)</a></li>
135<li><a
136href="{@docRoot}guide/developing/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up
137a library project (Command line)</a></li>
138</ul>
139
140
141
142<p>If you’re converting an existing application to use multiple APK support,
143scour your codebase for every localized string file, list of values, theme
144colors, menu icons and layout that isn’t going to change across APKs, and put
145it all in the library project.  Code that isn’t going to change much should
146also go in the library project.  You’ll likely find yourself extending these
147classes to add a method or two from APK to APK.</p>
148
149<p>If, on the other hand, you’re creating the application from scratch, try as
150much as possible to write code in the library project <em>first</em>, then only move it down to an
151individual APK if necessary.  This is much easier to manage in the long run than adding it to one,
152then another, then another, then months later trying to figure out whether this blob can be moved up
153to 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 you’re going to release.  For easy
159organization, place the library project and all related APK projects under the same parent folder. 
160Also remember that each APK needs to have the same package name, although they don’t necessarily
161need to share the package name with the library.  If you were to have 3 APKs following the scheme
162described earlier, your root directory might look like this:</p>
163
164<pre class="no-pretty-print classic">
165alexlucas:~/code/multi-apks-root$ ls
166foo-blue
167foo-green
168foo-lib
169foo-red
170</pre>
171
172<p>Once the projects are created, add the library project as a reference to each APK project.  If
173possible, define your starting Activity in the library project, and extend that Activity in your APK
174project.  Having a starting activity defined in the library project gives you a chance to put all
175your application initialization in one place, so that each individual APK doesn’t have to
176re-implement "universal" tasks like initializing Analytics, running licensing checks, and any other
177initialization procedures that don’t 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 Android Market, the correct
182APK 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>
189By way of example, let’s take the set of multiple APKs described earlier, and assume that each APK
190has been set to support all screen sizes larger than its "target" screen size.  Taken individually,
191the 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>
216However, by using the "highest version number wins" rule, if we set the versionCode attribute in
217each 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>
229Now, let’s further assume that the Red APK has some requirement on it that the other two don’t.  The
230<a href="{@docRoot}guide/appendix/market-filters.html">Market Filters page</a> of the Android
231Developer guide has a whole list of possible culprits.  For the sake of example, let’s assume that
232red requires a front-facing camera.  In fact, the entire point of the red APK is to use the extra
233available screen space to do entertaining things with that front-facing camera.  But, it turns out,
234not all xlarge devices even HAVE front-facing cameras!  The horror!</p>
235
236<p>Fortunately, if a user is browsing Market from one such device, Android Market will look at the
237manifest, see that Red lists the front-facing camera as a requirement, and quietly ignore it, having
238determined that Red and that device are not a match made in digital heaven.  It will then see that
239Green is not only compatible with xlarge devices, but also doesn’t care whether or not there’s a
240front-facing camera!  The app can still be downloaded from Android Market by the user, because
241despite the whole front-camera mishap, there was still an APK that supported that particular screen
242size.</p>
243
244<p>  In order to keep all your APKs on separate "tracks", it’s important to have a good version code
245scheme.  The recommended one can be found on the <a
246href="{@docRoot}guide/market/publishing/multiple-apks.html#VersionCodes">Version Codes</a> area of
247our developer guide.  Since the example set of APKs is only dealing with one of 3 possible
248dimensions, it would be sufficient to separate each APK by 1000 and increment from there.  This
249might look like:</p>
250
251<p>Blue: 1001, 1002, 1003, 1004...<br />
252Green: 2001, 2002, 2003, 2004...<br />
253Red:3001, 3002, 3003, 3004...</p>
254
255<p>  Putting this all together, your Android Manifests would likely look something like the
256following:</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>
291Note that technically, multiple APK’s will work with either the supports-screens
292tag, or the compatible-screens tag.  Supports-screens is generally preferred,
293and it’s generally a really bad idea to use both tags in the same manifest.  It
294makes things needlessly complicated, and increases the opportunity for errors.
295Also note that instead of taking advantage of the default values (small and
296normal are always true by default), the manifests explicitly set the value for
297each screen size.  This can save you headaches down the line.  For instance, a manifest with a
298target SDK of &lt; 9 will have xlarge automatically set to false, since that size didn’t exist yet. 
299So be explicit!
300</p>
301
302<h2 id="PreLaunch">Go Over Pre-launch Checklist</h2>
303<p>  Before uploading to Android Market, double-check the following items.  Remember that these are
304specifically relevant to multiple APKs, and in no way represent a complete checklist for all
305applications being uploaded to Android Market.</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
310you want it to avoid, set to false</li>
311<li>Double check your manifest filters for conflicting information (an APK that only supports
312cupcake on XLARGE screens isn’t 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
314platform version</li>
315<li>Try to test each APK on at least one device.  Barring that, you have one of the most
316customizable device emulators in the business sitting on your development machine.  Go nuts!</li>
317</ul>
318
319<p>It’s also worth inspecting the compiled APK before pushing to market, to make sure there aren’t
320any surprises that could hide your application in Market.  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
322packaging 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
326package: name='com.example.hello' versionCode='1' versionName='1.0'
327sdkVersion:'11'
328uses-permission:'android.permission.SEND_SMS'
329application-label:'Hello'
330application-icon-120:'res/drawable-ldpi/icon.png'
331application-icon-160:'res/drawable-mdpi/icon.png'
332application-icon-240:'res/drawable-hdpi/icon.png'
333application: label='Hello' icon='res/drawable-mdpi/icon.png'
334launchable-activity: name='com.example.hello.HelloActivity'  label='Hello' icon=''
335uses-feature:'android.hardware.telephony'
336uses-feature:'android.hardware.touchscreen'
337main
338supports-screens: 'xlarge'
339supports-any-density: 'true'
340locales: '--_--'
341densities: '120' '160' '240'
342</pre>
343
344<p>When you examine aapt output, be sure to check that you don’t have conflicting values for
345supports-screens and compatible-screens, and that you don’t have unintended "uses-feature" values
346that were added as a result of permissions you set in the manifest. In the example above, the APK
347will 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, Market 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
351manifest:</p>
352<pre>
353&lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;
354</pre>
355<p>Once you’ve completed the pre-launch checklist, upload your APKs to Android Market.  It may take a bit for the application to show up when browsing Android Market, 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>
356