summaryrefslogtreecommitdiffstats
path: root/docs/html/training/multiple-apks/multiple.jd
blob: 0c49705dbc367e444ed348ee3527bd52cd574d73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
page.title=Creating Multiple APKs with 2+ Dimensions
parent.title=Maintaining Multiple APKs
parent.link=index.html

trainingnavtop=true
previous.title=Creating Multiple APKs for Different GL Textures
previous.link=texture.html

@jd:body

<style>
.blueCell { background-color: #9fc5e8;}
.greenCell { background-color: #b6d7a8;}
.redCell { background-color: #ea9999;}
.purpleCell { background-color: #b4a7d6;}
.blackCell { background-color: #000000;}
</style>

<div id="tb-wrapper">
<div id="tb">

<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
  <li><a href="#Confirm">Confirm You Need Multiple APKs</a></li>
  <li><a href="#ChartReqs">Chart Your Requirements</a></li>
  <li><a href="#CreateLibrary">Put All Common Code and Resources in a Library Project.</a></li>
  <li><a href="#CreateAPKs">Create New APK Projects</a></li>
  <li><a href="#AdjustManifests">Adjust the Manifests</a></li>
  <li><a href="#PreLaunch">Go Over Pre-launch Checklist</a></li>
</ol>

<!-- other docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
  <li><a href="http://developer.android.com/guide/market/publishing/multiple-apks.html">Multiple APK
Support</a></li>
</ul>

</div>
</div>

<p>When developing your Android application to take advantage of multiple APKs on Google Play,
it’s important to adopt some good practices from the get-go, and prevent unnecessary headaches
further into the development process.  This lesson shows you how to create multiple APKs of your
app, each covering a different class of screen size.  You will also gain some tools necessary to
make maintaining a multiple APK codebase as painless as possible.</p>


<h2 id="Confirm">Confirm You Need Multiple APKs</h2>

<p>When trying to create an application that works across the huge range of available Android
devices, naturally you want your application look its best on each individual device.  You want to
take advantage of the space of large screens but still work on small ones, to use new Android API
features or visual textures available on cutting edge devices but not abandon older ones.  It may
seem at the outset as though multiple APK support is the best solution, but this often isn’t the
case.  The <a href="{@docRoot}guide/market/publishing/multiple-apks.html#ApiLevelOptions">Using
Single APK Instead</a> section of the multiple APK guide includes some useful information on how to
accomplish all of this with a single APK, including use of our <a
href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">support library</a>,
and links to resources throughout the Android Developer guide.</p>

<p>If you can manage it, confining your application to a single APK has several advantages,
including:</p>

<ul>
<li>Publishing and Testing are easier</li>
<li>There’s only one codebase to maintain</li>
<li>Your application can adapt to device configuration changes</li>
<li>App restore across devices just works</li>
<li>You don’t have to worry about market preference, behavior from "upgrades" from one APK to the
next, or which APK goes with which class of devices</li>
</ul>

<p>The rest of this lesson assumes that you’ve researched the topic, studiously absorbed the
material in the resources linked, and determined that multiple APKs are the right path for your
application.</p>


<h2 id="ChartReqs">Chart Your Requirements</h2>

<p>Start off by creating a simple chart to quickly determine how many APKs you need, and what screen
size(s) each APK covers.  Fortunately, it’s easy to chart out your requirements quickly, easily, and
have an easy reference for later.  Let’s say you want to split your APKs across two dimensions, API
and screen size.  Create a table with a row and column for each possible pair of values, and color
in some "blobs", each color representing one APK.</p>

<table cellpadding="10" cellspacing="0" border="1">
  <tbody>
    <tr>
      <td></td>
      <td>3</td>
      <td>4</td>
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
      <td>9</td>
      <td>10</td>
      <td>11</td>
      <td>12</td>
      <td>+</td>
    </tr>
    <tr>
      <td>small</td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
    <tr>
      <td>normal</td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
    <tr>
      <td>large</td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
    <tr>
      <td>xlarge</td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
  </tbody>
</table>

<p>
Above is an example with four APKs. Blue is for all small/normal screen devices, Green is for large
screen devices, and Red is for xlarge screen devices, all with an API range of 3-10.  Purple is a
special case, as it’s for all screen sizes, but only for API 11 and up.  More importantly, just by
glancing at this chart, you immediately know which APK covers any given API/screen-size combo.  To
boot, you also have swanky codenames for each one, since "Have we tested red on the ?" is a lot
easier to ask your cubie than "Have we tested  the 3-to-10 xlarge APK against the Xoom?"  Print this
chart out and hand it to every person working on your codebase.  Life just got a lot easier.</p>

<h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project.</h2>

<p>Whether you’re modifying an existing Android application or starting one from scratch, this is
the first thing that you should do to the codebase, and by the far the most important.  Everything
that goes into the library project only needs to be updated once (think language-localized strings,
color themes, bugs fixed in shared code), which improves your development time and reduces the
likelihood of mistakes that could have been easily avoided.</p>

<p class="note"><strong>Note:</strong>  While the implementation details of how to create and
include library projects are beyond the scope of this lesson, you can get up to speed quickly on
their creation at the following links:</p>
<ul>
<li><a
href="{@docRoot}guide/developing/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up
a library project (Eclipse)</a></li>
<li><a
href="{@docRoot}guide/developing/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up
a library project (Command line)</a></li>
</ul>

<p>If you’re converting an existing application to use multiple APK support,
scour your codebase for every localized string file, list of values, theme
colors, menu icons and layout that isn’t going to change across APKs, and put
it all in the library project.  Code that isn’t going to change much should
also go in the library project.  You’ll likely find yourself extending these
classes to add a method or two from APK to APK.</p>

<p>If, on the other hand, you’re creating the application from scratch, try as
much as possible to write code in the library project <em>first</em>, then only move it down to an
individual APK if necessary.  This is much easier to manage in the long run than adding it to one,
then another, then another, then months later trying to figure out whether this blob can be moved up
to the library section without screwing anything up.</p>

<h2 id="CreateAPKs">Create New APK Projects</h2>
<p>There should be a separate Android project for each APK you’re going to release.  For easy
organization, place the library project and all related APK projects under the same parent folder. 
Also remember that each APK needs to have the same package name, although they don’t necessarily
need to share the package name with the library.  If you were to have 3 APKs following the scheme
described earlier, your root directory might look like this:</p>

<pre class="no-pretty-print classic">
alexlucas:~/code/multi-apks-root$ ls
foo-blue
foo-green
foo-lib
foo-purple
foo-red
</pre>

<p>Once the projects are created, add the library project as a reference to each APK project.  If
possible, define your starting Activity in the library project, and extend that Activity in your APK
project.  Having a starting activity defined in the library project gives you a chance to put all
your application initialization in one place, so that each individual APK doesn’t have to
re-implement "universal" tasks like initializing Analytics, running licensing checks, and any other
initialization procedures that don’t change much from APK to APK.</p>


<h2 id="AdjustManifests">Adjust the Manifests</h2>
<p>When a user downloads an application which uses multiple APKs through Google Play, the correct
APK to use is chosen using two simple rules:

<ul>
<li>The manifest has to show that particular APK is eligible</li>
<li>Of the eligible APKs, highest version number wins.</li>
</ul>

<p>By way of example, let’s take the set of multiple APKs described earlier, and assume that each
APK has been set to support all screen sizes larger than its "target" screen size.  Let’s look at
the sample chart from earlier:</p>

<table cellpadding="10" cellspacing="0" border="1">
  <tbody>
    <tr>
      <td></td>
      <td>3</td>
      <td>4</td>
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
      <td>9</td>
      <td>10</td>
      <td>11</td>
      <td>12</td>
      <td>+</td>
    </tr>
    <tr>
      <td>small</td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
    <tr>
      <td>normal</td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="blueCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
    <tr>
      <td>large</td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="greenCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
    <tr>
      <td>xlarge</td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="redCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
      <td class="purpleCell"></td>
    </tr>
  </tbody>
</table>
<p>Since it’s okay for coverage to overlap, we can describe the area covered by each APK like
so:</p>
<ul>
<li>Blue covers all screens, minSDK 3.</li>
<li>Green covers Large screens and higher, minSDK 3.</li>
<li>Red covers XLarge screens (generally tablets), minSDK of 9.</li>
<li>Purple covers all screens, minSDK of 11.</li>
</ul>
<p>Note that there’s a <em>lot</em> of overlap in those rules.  For instance, an
XLarge device with API 11 can conceivably run any one of the 4 APKs specified.
However, by using the "highest version number wins" rule, we can set an order of
preference as follows:</p>
<p>
Purple &#8805; Red &#8805; Green &#8805; Blue
</p><p>
Why allow all the overlap?  Let’s pretend that the Purple APK has some requirement on it that the
other two don’t.  The <a href="{@docRoot}guide/appendix/market-filters.html">Filters on Google Play</a> page
of the Android Developer guide has a whole list of possible culprits.  For the sake of example,
let’s assume that Purple requires a front-facing camera.  In fact, the entire point of Purple is to
use entertaining things with the front-facing camera!  But, it turns out, not all API 11+ devices
even HAVE front-facing cameras!  The horror!</p>

<p>Fortunately, if a user is browsing Google Play from one such device, Google Play will look at the
manifest, see that Purple lists the front-facing camera as a requirement, and quietly ignore it,
having determined that Purple and that device are not a match made in digital heaven.  It will then
see that Red is not only compatible with xlarge devices, but also doesn’t care whether or not
there’s a front-facing camera!  The app can still be downloaded from Google Play by the user,
because despite the whole front-camera mishap, there was still an APK that supported that particular
API level.</p>

<p>  In order to keep all your APKs on separate "tracks", it’s important to have a good version code
scheme.  The recommended one can be found on the <a
href="{@docRoot}guide/market/publishing/multiple-apks.html#VersionCodes">Version Codes</a> area of
our developer guide.  It’s worth reading the whole section, but the basic gist is for this set of
APKs, we’d use two digits to represent the minSDK, two to represent the min/max screen size, and 3
to represent the build number.  That way, when the device upgraded to a new version of Android,
(say, from 10 to 11), any APKs that are now eligible and preferred over the currently installed one
would be seen by the device as an "upgrade".  The version number scheme, when applied to the example
set of APKs, might look like:</p>

<p>Blue: 0304001, 0304002, 0304003...<br />
Green: 0334001, 0334002, 0334003<br />
Red: 0344001, 0344002, 0344003...<br />
Purple: 1104001, 1104002, 1104003...<br />
</p>

<p>  Putting this all together, your Android Manifests would likely look something like the
following:</p>
<p>Blue:</p>
<pre>
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0304001" android:versionName="1.0" package="com.example.foo"&gt;
    &lt;uses-sdk android:minSdkVersion="3" /&gt;
    &lt;supports-screens android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" /&gt;
    ...
</pre>

<p>Green:</p>
<pre>
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0334001" android:versionName="1.0" package="com.example.foo"&gt;
    &lt;uses-sdk android:minSdkVersion="3" /&gt;
    &lt;supports-screens android:smallScreens="false"
        android:normalScreens="false"
        android:largeScreens="true"
        android:xlargeScreens="true" /&gt;
    ...
</pre>

<p>Red:</p>
<pre>
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0344001" android:versionName="1.0" package="com.example.foo"&gt;
    &lt;uses-sdk android:minSdkVersion="3" /&gt;
    &lt;supports-screens android:smallScreens="false"
        android:normalScreens="false"
        android:largeScreens="false"
        android:xlargeScreens="true" /&gt;
    ...
</pre>

<p>Purple:</p>
<pre>
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1104001" android:versionName="1.0" package="com.example.foo"&gt;
    &lt;uses-sdk android:minSdkVersion="11" /&gt;
    &lt;supports-screens android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" /&gt;
    ...
</pre>

<p>
Note that technically, multiple APK’s will work with either the supports-screens tag, or the
compatible-screens tag.  Supports-screens is generally preferred, and it’s generally a really bad
idea to use both-  It makes things needlessly complicated, and increases the opportunity for errors.
 Also note that instead of taking advantage of the default values (small and normal are always true
by default), the manifests explicitly set the value for each screen size.  This can save you
headaches down the line - By way of example, a manifest with a target SDK of &lt; 9 will have xlarge
automatically set to false, since that size didn’t exist yet.  So be explicit!
</p>

<h2 id="PreLaunch">Go Over Pre-launch Checklist</h2>
<p>  Before uploading to Google Play, double-check the following items.  Remember that these are
specifically relevant to multiple APKs, and in no way represent a complete checklist for all
applications being uploaded to Google Play.</p>
<ul>
<li>All APKs must have the same package name.</li>
<li>All APKs must be signed with the same certificate.</li>
<li>If the APKs overlap in platform version, the one with the higher minSdkVersion must have a
higher version code.</li>
<li>Every screen size you want your APK to support, set to true in the manifest.  Every screen size
you want it to avoid, set to false.</li>
<li>Double check your manifest filters for conflicting information (an APK that only supports
cupcake on XLARGE screens isn’t going to be seen by anybody)</li>
<li>Each APK's manifest must be unique across at least one of supported screen, OpenGL texture, or
platform version.</li>
<li>Try to test each APK on at least one device.  Barring that, you have one of the most
customizable device emulators in the business sitting on your development machine.  Go nuts!</li>
</ul>

<p>It’s also worth inspecting the compiled APK before pushing to market, to make sure there aren’t
any surprises that could hide your application on Google Play.  This is actually quite simple using the
"aapt" tool.  Aapt (the Android Asset Packaging Tool) is part of the build process for creating and
packaging your Android applications, and is also a very handy tool for inspecting them. </p>

<pre class="no-pretty-print classic">
&gt;aapt dump badging
package: name='com.example.hello' versionCode='1' versionName='1.0'
sdkVersion:'11'
uses-permission:'android.permission.SEND_SMS'
application-label:'Hello'
application-icon-120:'res/drawable-ldpi/icon.png'
application-icon-160:'res/drawable-mdpi/icon.png'
application-icon-240:'res/drawable-hdpi/icon.png'
application: label='Hello' icon='res/drawable-mdpi/icon.png'
launchable-activity: name='com.example.hello.HelloActivity'  label='Hello' icon=''
uses-feature:'android.hardware.telephony'
uses-feature:'android.hardware.touchscreen'
main
supports-screens: 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '120' '160' '240'
</pre>

<p>When you examine aapt output, be sure to check that you don’t have conflicting values for
supports-screens and compatible-screens, and that you don’t have unintended "uses-feature" values
that were added as a result of permissions you set in the manifest. In the example above, the APK
will be invisible to most, if not all devices.</p>
<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.
</p>
<p>Fortunately this is easily fixed by adding the following to your manifest:<p>
<pre>
&lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;
</pre>

<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>