Shape of the thing70 files
Only 44 KB of the APK is Dalvik bytecode, and almost none of it is Minecraft. The classes.dex holds 44 classes: 25 are Google's License Verification Library, a handful are a preferences screen and an ASCII-only text field, and exactly one matters — MainActivity, a subclass of NativeActivity that exists to hand 47 methods down to C++ over JNI.
Everything else lives in libminecraftpe.so. The build is against OpenGL ES 1.x fixed-function — libGLESv1_CM.so, no shaders anywhere — with libOpenSLES.so for audio and the NDK's android_native_app_glue event loop for input.
That list is the whole platform layer. setIsPowerVR is a per-GPU workaround flag; the Java side logs "Is PowerVR? : " and "Experimental on this device!" next to it. And postScreenshotToFacebook is the other half of the in-game camera item — screenshots land at /games/com.mojang/img_0000.jpg.
The composition problem4.49 MB unpacked
The APK ships zero audio files. Every asset is a PNG. The sounds are 43 raw PCM arrays compiled directly into the .data section of the shared library as C constants — PCM_zombie3, PCM_grass1, PCM_door_open — and they account for 99.9% of that section.
.text19.6%28 seconds of audio, stored at CD quality, is the single largest thing in Minecraft Pocket Edition. Each array carries a 16-byte header that makes the format self-describing:
// PCM_grass1, .data @ 0x19ffd4 01 00 00 00 channels = 1 (mono) 02 00 00 00 bytesPerSample= 2 (16-bit signed) 44 ac 00 00 sampleRate = 44100 22 56 00 00 numSamples = 22050 (0.500 s) ... 44100 bytes of interleaved PCM ...
All 43 headers validate against their symbol sizes exactly, so the set extracts losslessly to WAV. The encoding is also not quite consistent: splash is the lone 11025 Hz clip, and click is the lone stereo one.
| Group | Clips | Bytes | Note |
|---|---|---|---|
| zombie | 6 | 678,136 | idle ×3, hurt ×2, death |
| sheep | 3 | 253,624 | only other mob voice |
| footsteps | 20 | 693,352 | cloth, grass, gravel, sand, stone, wood |
| glass | 3 | 183,018 | break |
| world | 7 | 299,478 | explode, splash, pop, click, doors |
| hurt | 1 | 86,392 | player damage |
The code names mob.chicken, mob.cow, mob.pig and their hurt/death variants, but no PCM_ array exists for any of them. Chickens, cows and pigs are silent in this build. The texture misc/vignette.png is likewise requested by the renderer and absent from the APK.
Symbols7,915 dynamic entries
file reports the library as stripped, which is true only of the debug tables. The dynamic symbol table survives at full width — a 273 KB .dynstr — so every C++ class, method signature and static member is legible by name. 425 vtables recover the type hierarchy outright.
The names are the giveaway: Tile, Level, Mob, Tesselator, ItemInstance, LevelChunk, HitResult, Mth. These are not fresh C++ inventions — they are the MCP deobfuscation names from Minecraft Beta's Java source, carried over one-for-one. Pocket Edition was a hand port of the desktop codebase, and it kept the desktop vocabulary.
The application class is named NinecraftApp.
| Class | Methods | Role |
|---|---|---|
| Tile | 157 | block behaviour base |
| Level | 132 | world state + ticking |
| Item | 84 | item base |
| Entity | 81 | entity base |
| Mob | 68 | living entity |
| Player | 53 | |
| Minecraft | 50 | game root |
| Inventory | 48 | |
| LevelRenderer | 34 | |
| Tesselator | 31 | immediate-mode geometry |
Content inventory58 blocks · 47 items
Static members on Tile and Item enumerate the registry directly. Note emerald throughout — in Beta-era naming that is diamond, and the parallel string table confirms it, listing oreDiamond and pickaxeDiamond against the same slots.
Eight mob textures ship. Five of those mobs have an entity class behind them.
| Mob | Texture | Model | Renderer | Entity class | Sound |
|---|---|---|---|---|---|
| Pig | yes | yes | yes | yes | — |
| Cow | yes | yes | yes | yes | — |
| Chicken | yes | yes | yes | yes | — |
| Sheep | yes | yes | yes | yes | yes |
| Zombie | yes | yes | shared | yes | yes |
| Creeper | yes | yes | yes | no | — |
| Spider | yes | yes | yes | no | — |
| Skeleton | yes | yes | shared | no | — |
| TripodCamera | item/ | — | yes | yes | — |
Creeper, spider and skeleton are half-built: art and rendering code present, no entity, no AI, no spawn path. CreeperRenderer::getOverlayColor — the flash-white-before-detonating routine — exists for a creeper that cannot be created. Zombie is the only hostile mob with a real implementation.
TripodCamera is the pair to the camera item: place it, it photographs you, and the shot goes out through postScreenshotToFacebook.
The full Beta biome table, driven by PerlinNoise and ImprovedNoise, with worldgen features for trees (oak, birch, pine, spruce), ore, clay, flowers, reeds, cactus, springs and LargeCaveFeature.
Negative spacethe interesting part
Absences in a symbol table are strong evidence, because a stripped-but-exported binary hides nothing. Searching the full 7,915 symbols for crafting turns up exactly one hit: Item::hasCraftingRemainingItem(), a vestigial method inherited from the Java port with no system attached to it.
No crafting, no smelting, no storage. There is ore in the ground and a diamond pickaxe class in the registry, with no path in the game connecting them — CreativeMode hands you blocks and SurvivalMode lets you break them, and that is the whole loop. There are also no sounds for it: the Synth class is present but the ambient and music systems are not.
Only one ABI is shipped — armeabi-v7a. No ARMv5, no x86. A 2012 device without a v7a chip could install this APK and never launch it.
Multiplayer30 packet types
Networking is RakNet, vendored into the tree rather than linked. The transport is LAN broadcast to 255.255.255.255, advertising with the string MCCPP;Demo; — the UI calls it "Scanning for WiFi Games…". There is no account system, no server list, no internet play; the only remote hostname compiled in is localhost.
The protocol is a flat set of 30 packets split between ClientSideNetworkHandler and ServerSideNetworkHandler, with one player acting as host:
Version negotiation is a single integer compare, producing the two failure strings "Could not connect: Outdated client!" and "Could not connect: Outdated server!". The client is not trusted blindly — "Attempted to modify local player's inventory" is a guard in the client-side handler.
Save formatNBT, inherited
The full NBT tag hierarchy is ported intact — EndTag through CompoundTag, with the human-readable TAG_Byte_Array / TAG_Compound debug names still compiled in. Worlds live on external storage:
/sdcard/games/com.mojang/minecraftWorlds/<world>/ level.dat RandomSeed, GameType, LevelName, LastPlayed, SizeOnDisk, StorageVersion, Platform, Player chunks.dat RegionFile — single-file McRegion variant player.dat entities.dat
ExternalFileLevelStorageSource::requiresConversion and the StorageVersion / generatorVersion fields are already present, so the format was versioned for migration from the start — three weeks into the product's life.
Provenancebuild tree leak
RakNet's assertion macros bake __FILE__ into the release build, which preserves the absolute path of the machine that compiled it:
C:\dev\subversion\mojang\minecraftcpp\trunk\handheld\project
\lib_projects/raknet/jni/RakNetSources/ReliabilityLayer.cpp
Four things fall out of one string. The project was called minecraftcpp, not Pocket Edition. It was under Subversion, on trunk. It was built on Windows, from C:\dev. And handheld as a path component alongside lib_projects suggests the multi-platform structure that would later carry this engine to consoles.
Signed with Mojang AB's own certificate, self-issued in Stockholm on 7 August 2011 — nine days before Pocket Edition's first release — with a 2038 expiry. 2048-bit RSA, SHA-1. Genuine retail build.
0.1.0 shipped exclusively for Sony Ericsson's Xperia Play. This build still declares that heritage, but defanged:
<meta-data android:name="xperiaplayoptimized_content" …/> <uses-library android:name="xperiaplaycertified" android:required="false"/>
required="false" is the one attribute that makes the difference. The Xperia gamepad integration is still declared, so the device that launched the game keeps its optimised path — but the library is now optional, so Google Play will serve the APK to any ARMv7 handset running Gingerbread. That single boolean is the mechanism behind "0.2.0 runs on everything".
The paid and demo builds also share one binary: Minecraft_Market and Minecraft_Market_Demo both ship in this DEX, and the native side carries the demo's screens — DemoChooseLevelScreen, BuyButton, "Not available in the demo version". Only the manifest's launcher entry decides which one you get.
Methodno apktool required
objdump -T plus c++filt over 7,915 dynamic entries; classes recovered from vtable for / typeinfo for prefixes, method ownership from top-level :: splitting that respects template brackets.apktool or JVM was available in this environment..data symbol addresses mapped to file offsets through the section VMA delta (0x8000), headers decoded, all 43 clips written out as WAV with every length field checked against its symbol size.The extracted sounds are on disk at …/scratchpad/pe/sounds/ — 43 WAVs, 2.25 MB.