<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Android on Trevor's Blog</title><link>http://mings.in/en/tags/android/</link><description>Recent content in Android on Trevor's Blog</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 20 Oct 2026 10:49:18 +0800</lastBuildDate><atom:link href="http://mings.in/en/tags/android/index.xml" rel="self" type="application/rss+xml"/><item><title>My Google Play Account Got Banned, So I Opened a New One</title><link>http://mings.in/en/posts/gplay-reopen/</link><pubDate>Tue, 20 Oct 2026 10:49:18 +0800</pubDate><guid>http://mings.in/en/posts/gplay-reopen/</guid><description>The day my account got banned, my first reaction was the same as yours: register another one.</description><content:encoded><![CDATA[<h2 id="before-you-register-work-out-how-you-lost-the-last-one">Before you register, work out how you lost the last one</h2>
<p>The day my account got banned, my first reaction was the same as yours: register another one.</p>
<p>But after going through the official docs I realized reopening is not a process problem at all. It splits into two cases, and the outcomes are very different.</p>
<p>The first is dormancy. If an account goes a long time without publishing updates, checking stats or managing store listings, Google deactivates it. The help center says: after a dormant account is deactivated, you can still create a new account and publish on Google Play later. For that kind of account, reopening is routine.</p>
<p>The second is termination for violation. The same article says: if you repeatedly or seriously violate these policies or the developer distribution agreement, your developer account or related Google Play developer accounts may be terminated.</p>
<p>Pay attention to the words &ldquo;related&rdquo;. Another page puts it more bluntly: multiple warnings may lead to termination of the individual account and related Google Play developer accounts.</p>
<p>So the real question is not &ldquo;how do I reopen&rdquo;. It&rsquo;s &ldquo;will the new one survive&rdquo;.</p>
<p><img alt="First work out which case you&rsquo;re in" loading="lazy" src="/images/gplay-reopen/fig1.png"></p>
<h2 id="why-i-still-picked-a-personal-account">Why I still picked a personal account</h2>
<p>When you reopen, the account type step matters more than it did the first time.</p>
<p>An organization account needs a D-U-N-S number, organization registration documents, and the authorized representative&rsquo;s ID, and all three have to line up with each other. A D-U-N-S application can take up to 30 days. The account is already gone; waiting another month is too slow.</p>
<p>A personal account needs one government-issued photo ID. Fewer documents, fewer places to get it wrong.</p>
<p>But don&rsquo;t pick it just to save effort. There&rsquo;s an official list: financial products and services, health apps, apps using VpnService, and government apps. Those four categories must use an organization account. If your app touches any one of them, a personal account won&rsquo;t show the problem up front, but review will kick it back later anyway.</p>
<h2 id="the-six-steps-to-reopen">The six steps to reopen</h2>
<p>Order matters here, especially step two. Step one is getting the Google account ready. Use a clean one, not an account that already registered another developer account, and don&rsquo;t buy one.</p>
<p>Step two: go to Google Payments first and create a payments profile. Country/region China, legal name and address exactly as printed on your ID. You can&rsquo;t skip this and can&rsquo;t bolt it on later.</p>
<p>Step three: register a developer account in Play Console with that account and pay $25. Cards accepted are MasterCard, Visa, American Express, Discover (US only) and Visa Electron (outside the US). Prepaid cards are not accepted.</p>
<p>Step four: choose a personal account.</p>
<p>Step five: identity verification, submitting a government-issued photo ID.</p>
<p>Step six: device verification. Find a real Android 10+ phone that isn&rsquo;t rooted, install the Play Console mobile app, scan the QR code. The docs say this takes a minute.</p>
<p><img alt="The six steps to reopen, with step two as the foundation" loading="lazy" src="/images/gplay-reopen/fig2.png"></p>
<p>Why can&rsquo;t you skip ahead? Phone verification comes after identity and device verification. Finish the earlier steps or the phone verification entry point never opens for you.</p>
<h2 id="after-approval-the-home-page-looks-like-this">After approval, the home page looks like this</h2>
<p>The day verification passed I got into Console and the first look is a letdown: 0 apps in production, 0 apps with policy tasks, 0 apps with publishing submissions. Three cards, all zeros.</p>
<p>That&rsquo;s correct. Passing only means you can create apps now. It doesn&rsquo;t mean an app can ship. The real starting point is that &ldquo;Create app&rdquo; button in the top right.</p>
<p>Two things on this page are worth noting. In the row of buttons at the top there&rsquo;s &ldquo;Policy status&rdquo;, and account reputation problems show up there first. In the list below, anything tagged Draft is an app you created but haven&rsquo;t submitted for review. That green banner in the middle is just a Play redesign notice and has nothing to do with your account status.</p>
<p><img alt="The Chinese Play Console home page after approval" loading="lazy" src="/images/gplay-reopen/fig4-console.jpg"></p>
<h2 id="the-address-section-ate-most-of-my-time">The address section ate most of my time</h2>
<p>Last time I filled the address in without thinking. Not this time.</p>
<p>The docs say this on the required documents by country page, and I copied it down:</p>
<blockquote>
<p>All documents you submit must match the information in your payments profile exactly, including personal identity details, organization name (for organization accounts), and address information. If you find any discrepancy between your documents and your payments profile, you can update the payments profile information during the verification task.</p>
</blockquote>
<p>That sentence explains why most people get rejected. Verification is not checking whether your documents are complete. It&rsquo;s checking whether they match what you typed in yourself.</p>
<p>Three lines have to match character for character.</p>
<p>Name: if the ID is in Chinese, write it in Chinese. Don&rsquo;t write &ldquo;张伟&rdquo; in one place and &ldquo;Zhang Wei&rdquo; in another.</p>
<p>Address: the address in the payments profile is the legal address, and the country/region Play displays publicly is based on it. If the ID says &ldquo;3号楼502, XX路128号, XX区&rdquo; and you only wrote &ldquo;XX路&rdquo;, that counts as a mismatch. Province, city, district, street, building, unit — write down as many levels as you can.</p>
<p>Documents: four hard requirements. Valid and unexpired, color not black and white, clearly legible with reasonable exposure, and not a photocopy.</p>
<p><img alt="Three lines that have to match character for character" loading="lazy" src="/images/gplay-reopen/fig3.png"></p>
<p>If you&rsquo;ve already been rejected you don&rsquo;t have to register again. The second half of that same sentence says you can update the payments profile during the verification task, fix the address to match the ID, and submit again.</p>
<h2 id="how-to-keep-the-new-account-from-getting-dragged-down">How to keep the new account from getting dragged down</h2>
<p>This is the part I most wanted to get right, because there&rsquo;s no trick to it. Only facts.</p>
<p>When Google says &ldquo;related developer accounts may be terminated&rdquo;, it means Google looks at whether a set of things are the same: the same person, the same payment card, the same device, the same batch of package names, the same payout account.</p>
<p>Open a new account and carry all those traces over unchanged, and you&rsquo;ve raised your hand to say &ldquo;still me&rdquo;.</p>
<p>What actually reduces risk is the reason the original account was banned being not that serious, or the appeal already settled. For serious violations like malware or fraud, ten new accounts won&rsquo;t help. Reopening in that situation means the $25 is gone and the account gets banned again.</p>
<p>Put bluntly, that phrase &ldquo;related developer accounts&rdquo; exists specifically to close this door.</p>
<h2 id="before-you-submit-check-the-files-locally">Before you submit, check the files locally</h2>
<p>Two of the four photo requirements can be checked right on a Mac: is it color, and is the resolution high enough. The built-in sips tool does it, nothing to install.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sips -g pixelWidth -g pixelHeight -g space your-id.jpg
</span></span></code></pre></div><p>Look at the space line. RGB means color. Gray means black and white, and a black and white image will always be rejected. If the short edge is under 1000 pixels, retake it: images passed through WeChat often end up only a few hundred pixels.</p>
<p>I wrote a small script to chain both checks, and the output looks like this:</p>
<pre tabindex="0"><code>id-color.png        1600×1000  space=RGB   ✓ pass
id-gray-small.png   640×400    space=Gray  ✗ short edge 400px  ✗ grayscale
</code></pre><h2 id="one-last-honest-word">One last honest word</h2>
<p>With reopening, the documents and the process are secondary. What comes first is always why the last account died.</p>
<p>Dormancy deactivation: just walk the six steps above. Termination for serious violation: don&rsquo;t count on a new account turning the page. Fix the problem first, then talk about registering.</p>
<p>Have you reopened one? Which step did you get stuck on? Comments welcome.</p>
]]></content:encoded></item><item><title>Google Play Registration: Your Address Has to Match Your ID</title><link>http://mings.in/en/posts/gplay-register/</link><pubDate>Tue, 20 Oct 2026 10:00:45 +0800</pubDate><guid>http://mings.in/en/posts/gplay-register/</guid><description>Someone asked me again last week what to do about a rejected Play developer account. Going through his materials: ID photographed, card linked, the $25 charged successfully. The problem was the address — his card&amp;rsquo;s billing address was the office, the address on his ID was his hometown.</description><content:encoded><![CDATA[<h2 id="the-most-common-rejection-is-not-missing-paperwork">The most common rejection is not missing paperwork</h2>
<p>Someone asked me again last week what to do about a rejected Play developer account. Going through his materials: ID photographed, card linked, the $25 charged successfully. The problem was the address — his card&rsquo;s billing address was the office, the address on his ID was his hometown.</p>
<p>There are plenty of Chinese tutorials on the registration flow. Almost none cover address alignment, even though Google puts this front and center in its help center.</p>
<h2 id="in-googles-own-words">In Google&rsquo;s own words</h2>
<blockquote>
<p>All documents you submit must match the information in your payments profile exactly, including: personal identity details, organization name (for organization accounts), and address. If you find any discrepancy between your document and your payments profile, you can update the payments profile while the verification task is in progress.</p>
</blockquote>
<p>Right after that comes a line about why it fails:</p>
<blockquote>
<p>Submitting unsupported documents is the leading cause of developer verification failure, and providing altered or forged documents can result in immediate removal of your account and apps.</p>
</blockquote>
<p>Those two sentences lay the rule out completely: verification is not about whether you have documents, it is about whether what you submit matches what you entered. If it does not match, complete paperwork is still wrong.</p>
<p><img alt="Three lines that have to match word for word" loading="lazy" src="/images/gplay-register/fig1.png"></p>
<h2 id="the-address-is-not-the-one-you-typed-on-the-signup-page">The address is not the one you typed on the signup page</h2>
<p>A lot of people think the address is just a field you fill in on the signup form. It is not.</p>
<p>Play&rsquo;s legal name and legal address come from the Google payments profile attached to your account. In other words, the address you store in Google Payments is what actually gets compared against your ID. The country and region shown publicly on your Play page are derived from that same legal address.</p>
<p>So the order is obvious: get the payments profile right first, then open the developer account. Doing it the other way plants a mine under your own review.</p>
<h2 id="three-lines-that-have-to-line-up">Three lines that have to line up</h2>
<p>The first is the name. If the name on your ID is in Chinese, write it in Chinese in the payments profile too. If the system only takes Latin characters, pick one transliteration rule and stick to it. Do not write 张伟 in one place and Zhang Wei in another, and definitely do not spell it out in one place and abbreviate it in another.</p>
<p>The second is the address. Province, city, district, street, building number — go as deep as the ID goes, and match the wording character for character. If the ID says XX District, XX Road, No. 128, Building 3, Unit 502 and your payments profile says XX Road, that counts as a mismatch.</p>
<p>The third is the photo of the document. The four official requirements are specific: valid and unexpired, color not black and white, legible with balanced exposure, and not a photocopy. Fail any one and it counts as an unsupported document.</p>
<p>One item that is not in the official text but comes up constantly in practice: the billing address on the card you link should ideally be the same address. No official basis for this one, just experience. Take it as a pointer.</p>
<h2 id="six-steps-for-registering-entirely-in-chinese">Six steps for registering entirely in Chinese</h2>
<p>Step one: make a clean Google account. Do not reuse an account that already registered another developer account, and do not use a bought one. Identity verification later checks the person.</p>
<p>Step two: go into Google Payments and create a payments profile, set country/region to China, and enter the legal name and address exactly as they appear on your ID. The address you enter here is what every later verification checks against.</p>
<p>Step three: register the developer account in the Play Console with that account and pay $25. Cards are limited to MasterCard, Visa, American Express, Discover (US only) and Visa Electron (outside the US). Prepaid cards are not accepted.</p>
<p>Step four: choose the account type. Personal account, pick individual. Do not force organization just because it looks more official — organization accounts need a D-U-N-S number and company documents, and one missing item stalls you.</p>
<p>Step five: identity verification, submit a government-issued photo ID. For a personal account that is the only document.</p>
<p>Step six: device verification. Take a real phone on Android 10 or later, not rooted, install the Play Console app, scan the QR code. One minute.</p>
<p><img alt="The six steps, with step two as the foundation" loading="lazy" src="/images/gplay-register/fig2.png"></p>
<p>You cannot skip around. Phone verification comes after these; until identity verification is done, the phone verification entry point does not even open.</p>
<h2 id="organization-accounts-need-two-more-documents-with-the-same-address-alignment">Organization accounts need two more documents, with the same address alignment</h2>
<p>An organization account needs the representative&rsquo;s ID plus the organization&rsquo;s registration document (a business license, typically) and a D-U-N-S number. The organization name and address on all three must match the payments profile character for character.</p>
<p>D-U-N-S is free to apply for on D&amp;B&rsquo;s own site, and Google specifically warns that third parties charge steep handling fees. Do not fall for it. Approval can take up to 30 days, so if you are going the organization route, start a month ahead.</p>
<h2 id="run-your-own-check-before-you-submit">Run your own check before you submit</h2>
<p>Two of the four official photo requirements can be checked locally: whether it is color, and whether the resolution is enough. macOS ships with sips, nothing to install.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sips -g pixelWidth -g pixelHeight -g space your-id.jpg
</span></span></code></pre></div><p>Look at the <code>space</code> line. <code>RGB</code> means color, <code>Gray</code> means black and white, and a black and white image will be rejected. If the short edge is under 1000 pixels, reshoot. Compressed WeChat images are often only a few hundred pixels.</p>
<p>I wrapped these checks in a small script. Here it is run against two sample images:</p>
<pre tabindex="0"><code>id-color.png        1600×1000  space=RGB   ✓ pass
id-gray-small.png   640×400    space=Gray  ✗ short edge only 400px  ✗ color space is Gray
</code></pre><p><img alt="The two checks you can run locally" loading="lazy" src="/images/gplay-register/fig3.png"></p>
<h2 id="what-if-you-already-got-rejected">What if you already got rejected</h2>
<p>You do not need to re-register. Google says you can update the payments profile while the verification task is in progress, change the address to match your ID, and submit again.</p>
<p>What is genuinely hopeless is forgery. An ID with the address edited in Photoshop, a borrowed ID, a bought business license — if they catch it, the account and apps are removed and the $25 is not refunded.</p>
<p>The address thing is tiny — one line of text. It is also huge, because it decides whether every verification after it passes. Did the address trip you up when you registered? Tell me in the comments.</p>
]]></content:encoded></item><item><title>A Google Play Developer Account: The Five Gates After the $25</title><link>http://mings.in/en/posts/gplay-dev-account/</link><pubDate>Mon, 19 Oct 2026 15:38:12 +0800</pubDate><guid>http://mings.in/en/posts/gplay-dev-account/</guid><description>Chinese tutorials on Play developer accounts mostly stopped updating two years ago: $25, a credit card, an address, wait a day. That is no longer enough.</description><content:encoded><![CDATA[<h2 id="twenty-five-dollars-only-buys-the-ticket">Twenty-five dollars only buys the ticket</h2>
<p>Chinese tutorials on Play developer accounts mostly stopped updating two years ago: $25, a credit card, an address, wait a day. That is no longer enough.</p>
<p>The help center now says: 18 or older, accept the developer distribution agreement, pay $25 by credit or debit card, cards limited to MasterCard, Visa, American Express, Discover (US only) and Visa Electron (outside the US), and prepaid cards are explicitly not accepted.</p>
<p>Paying the money only gets you through the door. After that comes identity verification, device verification, a closed test with twelve people over fourteen days, and the new rules that took effect September 30.</p>
<p><img alt="The six steps to open an account" loading="lazy" src="/images/gplay-dev-account/fig2.png"></p>
<h2 id="personal-or-organization-pick-the-right-one-first">Personal or organization: pick the right one first</h2>
<p>Play has exactly two kinds of developer accounts: personal and organization. Same features, both can monetize, both can add collaborators.</p>
<p>The difference is paperwork. An organization account must supply a Dun &amp; Bradstreet number, D-U-N-S, the nine-digit business identifier issued by D&amp;B. It is free to apply for, but you wait. There is also a list: financial services, health apps, apps that use VpnService, and government apps. Those four categories must use an organization account.</p>
<p>A personal account registers fast. The price is that the testing requirements below aim specifically at personal accounts.</p>
<h2 id="identity-verification-the-id-and-the-card-have-to-be-the-same-person">Identity verification: the ID and the card have to be the same person</h2>
<p>The official wording: to process the registration application, they may ask for a valid government-issued photo ID and credit card information, and the holder of both must be you. If they check and the information turns out invalid, the registration fee is not refunded.</p>
<p>This one gets ignored a lot in China. Paying with someone else&rsquo;s card, or padding the file with a relative&rsquo;s ID, both count as inconsistent information. $25 is not a lot, but you do not get it back.</p>
<h2 id="device-verification-one-minute-but-you-need-a-real-phone">Device verification: one minute, but you need a real phone</h2>
<p>Since early 2024, a new personal account has to prove it has a real Android device before publishing anything. The method: scan a QR code with the Play Console mobile app, sign in to the same Google account, pick the developer account, tap verify.</p>
<p>The bar is a physical device on Android 10 or higher, not rooted. Emulators do not count, rooted devices do not count. Google says this should take under a minute, one device can verify multiple accounts, and the process does not collect the device&rsquo;s phone number.</p>
<h2 id="twelve-people-fourteen-days">Twelve people, fourteen days</h2>
<p>This is the one outdated tutorials get wrong most often. Plenty of articles still say find twenty testers and test for fourteen straight days. The official page now says: at least 12 testers who opted in to continuous participation in a closed test for at least the past 14 days.</p>
<p>The number changed and Chinese tutorials largely did not keep up. Per the current official wording, it is 12.</p>
<p>The rule only applies to personal accounts created after November 13, 2023. Once you satisfy it you can apply for production release access in the dashboard, and the application asks about app design, your testing process, and launch readiness.</p>
<h2 id="from-september-30-verification-reaches-past-play">From September 30, verification reaches past Play</h2>
<p>This part is the genuinely new thing. Android developer verification enters the enforcement phase on September 30, 2026, starting with four countries — Brazil, Indonesia, Singapore and Thailand — covering distribution across seven stores: Google Play, HONOR App Market, OPPO Software Store, Samsung Galaxy Store, Transsion Palm Store, vivo App Store, Xiaomi GetApps.</p>
<p>In other words, from now on installing an app on a certified device raises a question: who signed this package. The official timeline is worldwide rollout in 2027.</p>
<p><img alt="The rules got stacked on one layer at a time" loading="lazy" src="/images/gplay-dev-account/fig1.png"></p>
<p>It splits developers onto three paths, and identity verification, fees and where you can distribute all differ.</p>
<p><img alt="The trade-offs of the three distribution paths" loading="lazy" src="/images/gplay-dev-account/fig3.png"></p>
<p>Three key details.</p>
<p>Full distribution requires opening a separate account in the Android Developer Console, also $25, which is a different payment from the Play one. Limited distribution is free and needs no ID documents, but covers only 20 devices, and users have to accept an invitation before they can install. On the unverified sideload path, users can let themselves through via an advanced flow, which the official writeup describes as a buffer that buys users time and room.</p>
<p>One more detail matters most to people who write code. The official FAQ is blunt: installing an app over ADB requires no registration and no verification. Development, debugging, flashing your own test builds — that channel is not closed. Apps on enterprise-managed devices also skip verification; the IT admin has already reviewed them.</p>
<h2 id="what-registering-a-package-name-needs-you-can-prep-locally">What registering a package name needs, you can prep locally</h2>
<p>The third step of the new verification system is registering the package name. Google requires an APK signed with your private key, to prove the package is yours. You do not have to wait for the account to be approved for this — you can rehearse it locally.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">keytool -genkeypair -v -keystore demo.jks -storetype PKCS12 <span class="se">\
</span></span></span><span class="line"><span class="cl">  -alias upload -keyalg RSA -keysize <span class="m">4096</span> -validity <span class="m">10000</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -dname <span class="s2">&#34;CN=Demo Dev, O=Demo, C=CN&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">keytool -list -v -keystore demo.jks <span class="p">|</span> grep SHA256
</span></span></code></pre></div><p>What comes out is a SHA-256 string. Mine generated 52:05:B5:73:…, with another thirty bytes behind it. That fingerprint is what gets checked against package ownership from here on. Lose the private key and it never matches again. So from day one, treat the keystore file and its backup as the same object.</p>
<h2 id="the-math-cross-platform-developers-have-to-do">The math cross-platform developers have to do</h2>
<p>If you are shipping Android from one codebase with Kotlin Multiplatform or Flutter, the accounting splits here. $25 to publish on Play, another $25 to distribute outside Play through the Android Developer Console, and both accounts need identity verification.</p>
<p>Where you save is elsewhere: device verification and the twelve-people-fourteen-days test are tied only to a personal account&rsquo;s production release access. Organization accounts do not carry that.</p>
<p>The actually convenient move is to keep publishing through Play as usual, and register the package name and signing key in the Android Developer Console at the same time. Then no matter which store a user downloads from later, or whether they install straight from your site, the install does not get blocked.</p>
<p>$25 buys a ticket. The gates behind the ticket are where this year&rsquo;s time actually goes. Which step did you get stuck on when you opened your account? Comments are open.</p>
]]></content:encoded></item><item><title>The Agent's Official Command Line: Android CLI 1.0</title><link>http://mings.in/en/posts/android-cli/</link><pubDate>Wed, 14 Oct 2026 14:36:53 +0800</pubDate><guid>http://mings.in/en/posts/android-cli/</guid><description>You have an agent write some Kotlin. It says it&amp;rsquo;s done. Now what?</description><content:encoded><![CDATA[<h2 id="first-a-broken-link-in-the-chain">First, a broken link in the chain</h2>
<p>You have an agent write some Kotlin. It says it&rsquo;s done. Now what?</p>
<p>You open Android Studio yourself, watch Gradle spin, wait for the emulator, then poke the screen with your mouse to check whether that string actually changed. Inside the terminal the agent flies. At the point where you need to look at the screen, the chain snaps, and the rest of the work belongs to your eyes.</p>
<p>That gap is what Google just filled. Android CLI is at 1.0 stable. Their words:</p>
<blockquote>
<p>Whether you use Gemini in Android Studio, Antigravity 2.0 or Antigravity CLI, or a third-party agent like Anthropic&rsquo;s Claude Code or OpenAI&rsquo;s Codex, our mission stays the same: make high-quality Android development possible anywhere.</p>
</blockquote>
<p>Blunt enough. Whichever agent you use, they want you to stay in the terminal. I ran it end to end on this machine, from creating a project all the way to looking at the screen.</p>
<h2 id="what-it-actually-ships">What it actually ships</h2>
<p>I&rsquo;ll go through the list by what it saves your agent from doing.</p>
<h3 id="one-android-command">One android command</h3>
<p>After installing you get a single command, <code>android</code>, with 19 top-level subcommands. Creating projects, starting emulators, installing apps, looking at the screen, all of it:</p>
<pre tabindex="0"><code>auth completion create describe device docs emulator info init
install layout run screen sdk skills studio update help
</code></pre><p>Agents used to have to remember three sets of flags for adb, emulator and gradle. Now there is one entry point against one SDK. It installs a single 3.6 MB binary into your home directory, and afterward <code>android info</code> reports the SDK path and version.</p>
<h3 id="the-official-skills-library">The official skills library</h3>
<p><code>android init</code> is the interesting one. It takes no arguments, and when it finishes it has written a 24,922-byte <code>android-cli</code> skill into every agent&rsquo;s skill directory on your machine. It hit 10 on mine:</p>
<pre tabindex="0"><code>~/.claude/skills          ~/.gemini/skills           ~/.agents/skills
~/.commandcode/skills     ~/.hermes/skills           ~/.junie/skills
~/.openclaw/skills        ~/.config/opencode/skills  ~/.pi/agent/skills
~/.gemini/antigravity/skills
</code></pre><p>Hermes is in there, along with Claude Code, Codex, Gemini, OpenClaw and OpenCode. Worth looking at which directories it wrote into after it runs. It is dropping files in your home, after all.</p>
<p>There are 24 skills in the library now; <code>android skills list</code> shows them all. On the UI side: adaptive, camerax (camera migration), edge-to-edge, wear-compose-m3 (Wear OS).</p>
<p>There are a few project-hygiene ones too: play-policy-insights, restore-credentials, testing-setup, r8-analyzer. Installing is one line, <code>android skills add &lt;name&gt;</code>, and you can pick which agent gets it.</p>
<h3 id="an-offline-copy-of-the-official-docs">An offline copy of the official docs</h3>
<p><code>android docs search &quot;edge to edge&quot;</code> downloads an index on first run. 5,319 entries, measured. What comes back is not a URL but a <code>kb://android/...</code> protocol address.</p>
<p>Even the sample code inside skills is in there, e.g. <code>kb://android/agents/skills/wear/wear-compose-m3/references/material3/EdgeButtonSample.kt</code>. Agents no longer have to search blogs. The official docs are queryable locally.</p>
<h3 id="the-look-at-the-screen-commands">The look-at-the-screen commands</h3>
<p>This group is the most useful thing in the release. <code>screen capture --annotate</code> labels the elements on screen as <code>#1</code>, <code>#2</code>, and <code>screen resolve</code> turns those labels back into coordinates:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">android --no-metrics screen capture --annotate --output shots/12-annotated.png
</span></span><span class="line"><span class="cl">android --no-metrics screen resolve --screenshot shots/12-annotated.png --string <span class="s2">&#34;tap #1 and #2&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># output: tap 72 31 and 835 30</span>
</span></span></code></pre></div><p>The agent no longer does pixel math. It points at <code>#3</code> and says tap this. <code>layout</code> in the same group returns the UI tree as JSON, with <code>bounds</code> and center point for every control.</p>
<h3 id="borrowing-android-studios-semantic-analysis">Borrowing Android Studio&rsquo;s semantic analysis</h3>
<p>The new <code>android studio</code> subcommands: <code>find-declaration</code> for definitions, <code>find-usages</code> for references, <code>analyze-file</code> to run inspections, <code>render-compose-preview</code> to render a Compose preview, <code>version-lookup</code> for dependency versions, <code>open-file</code> to open a file in the IDE.</p>
<p>That means the agent borrows the IDE&rsquo;s fifteen-odd years of semantic analysis instead of guessing with regex. There is a floor: Android Studio Quail 1 or later.</p>
<h3 id="booking-a-physical-device">Booking a physical device</h3>
<p><code>android device remote</code> lets you book a remote physical device to run on. Their example connects to a Pixel 10 Pro. This path needs <code>android auth</code> and a Google account first.</p>
<h2 id="i-ran-it-from-zero-on-macos">I ran it from zero on macOS</h2>
<p>Only a clean run counts. These are the commands I actually ran, none left out:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># install: download the script and read it first, don&#39;t pipe straight into shell</span>
</span></span><span class="line"><span class="cl">curl -fsSL -o /tmp/android-cli-install.sh <span class="se">\
</span></span></span><span class="line"><span class="cl">  https://dl.google.com/android/cli/latest/darwin_arm64/install.sh
</span></span><span class="line"><span class="cl">bash /tmp/android-cli-install.sh            <span class="c1"># → ~/.local/bin/android, 3,650,880 bytes</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">android --no-metrics -V                     <span class="c1"># 1.0.16500706, first run walks you through the Android SDK terms</span>
</span></span><span class="line"><span class="cl">android init                                <span class="c1"># writes skills into each agent&#39;s skill directory</span>
</span></span><span class="line"><span class="cl">android --no-metrics skills list            <span class="c1"># official skill catalog, 24 measured</span>
</span></span><span class="line"><span class="cl">android --no-metrics docs search <span class="s2">&#34;edge to edge&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># end to end: create project → start emulator → build → install → look at screen</span>
</span></span><span class="line"><span class="cl">android --no-metrics create --name CliDemo <span class="se">\
</span></span></span><span class="line"><span class="cl">  --application-id com.example.clidemo --min-sdk <span class="m">36</span> -o ~/android-cli-repro/CliDemo
</span></span><span class="line"><span class="cl">android --no-metrics emulator list          <span class="c1"># existing AVD on my machine: Medium_Phone_API_36.1</span>
</span></span><span class="line"><span class="cl">android --no-metrics emulator start Medium_Phone_API_36.1   <span class="c1"># returns only when ready, about 17s</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ~/android-cli-repro/CliDemo
</span></span><span class="line"><span class="cl">./gradlew :app:assembleDebug                <span class="c1"># first build: BUILD SUCCESSFUL in 1m 24s</span>
</span></span><span class="line"><span class="cl">android --no-metrics run --apks app/build/outputs/apk/debug/app-debug.apk
</span></span><span class="line"><span class="cl">android --no-metrics screen capture --output shots/10-before.png
</span></span><span class="line"><span class="cl">android --no-metrics layout
</span></span></code></pre></div><p>Project creation first. <code>create</code> produces a Compose + AGP 9 + Kotlin 2.3.20 project. I never touched SDK Manager. It noticed <code>platforms/android-36</code> was missing and installed it.</p>
<p><code>emulator start</code> is a nicely designed piece: it blocks until the device is fully booted, printing remaining seconds along the way, so you never poll adb yourself. Ready in 17 seconds for me.</p>
<p>What actually surprised me was the second run. I changed one string, <code>listOf(&quot;Android&quot;)</code> to <code>listOf(&quot;Android CLI&quot;)</code> in the data source, and ran the loop again:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./gradlew :app:assembleDebug                <span class="c1"># incremental: BUILD SUCCESSFUL in 8s</span>
</span></span><span class="line"><span class="cl">android --no-metrics run --apks app/build/outputs/apk/debug/app-debug.apk
</span></span><span class="line"><span class="cl"><span class="c1"># Delta Install: Sent 167.94 KB patch instead of 28.67 MB (1 APK, 99.43% savings)</span>
</span></span></code></pre></div><p>The first install pushed 28.64 MB. The second pushed a 167.94 KB patch, 99.43% saved. Delta install is on by default (<code>--use-delta-install</code> defaults to true), and for the change-a-string-and-look loop, everything you save is waiting.</p>
<p>Reading the UI tree with <code>layout</code> afterward, the string is already the new one:</p>
<pre tabindex="0"><code>应用窗口: CliDemo  焦点=True  边界=[0,0][1080,2400]
  - android.widget.TextView | text=&#39;Hello Android CLI!&#39; | center=[220,136]
</code></pre><p><img loading="lazy" src="/images/android-cli/fig-loop.png"></p>
<p><img loading="lazy" src="/images/android-cli/fig-agent.png"></p>
<h2 id="the-entry-bar-and-a-few-pitfalls">The entry bar and a few pitfalls</h2>
<p>The one that trips you up fastest is <code>run</code>. Its description says build, deploy, launch. Without <code>--apks</code>, it just fails for me:</p>
<pre tabindex="0"><code>Error: No apks specified. Use --apks &lt;path1,path2,...&gt;
Component check failed
</code></pre><p>The APK was already built and <code>describe</code> had just located it. <code>run</code> still would not do it on its own. The actual split: producing the artifact belongs to the project&rsquo;s own <code>./gradlew</code>, <code>run</code> handles install and launch.</p>
<p>One more, sneakier. The package deploys but the UI does not change, because the old process is still alive and <code>run</code> will not force-kill it for you. Add <code>adb shell am force-stop com.example.clidemo</code> and run again.</p>
<p>There is a version floor too. The <code>android studio</code> commands need Quail 1 or later. Too old and you get <code>No running Studio instances found</code>, plus a line telling you to grab a newer build from the site.</p>
<p>Two more. <code>android init</code> writes files into your home directory, it is not a read-only operation, so if you have a lot of agents on the machine, read the list before you run it. And the subcommand is the singular <code>device</code>; <code>android device list</code> reports <code>'list' is not a valid command</code>.</p>
<p>Also <code>android completion</code> writes shell completion into your shell config. Do not run it if you do not want that touched.</p>
<p>Telemetry deserves a line. The CLI collects data by default. The docs say what: which subcommand ran, the parameter names used, and a set of fixed values such as emulator template names and agent names (<code>GEMINI</code>, <code>CLAUDE</code>, <code>CODEX</code>). Add <code>--no-metrics</code> if you do not want it. Every command above carries it.</p>
<h2 id="one-last-thing">One last thing</h2>
<p>This release did not invent a separate workflow for agents. It changed the things that already existed. Docs, skills, emulators, physical devices, IDE semantic analysis: all now exposed as interfaces a machine can read.</p>
<p>The details are handled too. Pixel coordinates become labels like <code>#3</code>, the UI tree comes back as JSON.</p>
<p>On your toolchain: would you hand the whole change-code-to-see-the-screen stretch over to an agent? Comments are open.</p>
]]></content:encoded></item><item><title>Android Is Tightening Sideloading, and Cross-Platform Devs Need to Redo Their Distribution Math</title><link>http://mings.in/en/posts/android-distro-cost/</link><pubDate>Fri, 09 Oct 2026 07:39:00 +0800</pubDate><guid>http://mings.in/en/posts/android-distro-cost/</guid><description>By the time a cross-platform project reaches release, there is usually more than one distribution path. One through Google Play, one straight from your own site, and sometimes a test build for the QA folks. Android&amp;rsquo;s developer verification reprices the entry cost of each path, and the three bills are not calculated the same way at all.</description><content:encoded><![CDATA[<p>By the time a cross-platform project reaches release, there is usually more than one distribution path. One through Google Play, one straight from your own site, and sometimes a test build for the QA folks. Android&rsquo;s developer verification reprices the entry cost of each path, and the three bills are not calculated the same way at all.</p>
<h2 id="three-paths-three-bills">Three paths, three bills</h2>
<p>Start with the Google Play path. For a team that already has a Play developer account, this bill is close to zero. The app is already inside the verification flow, packages using Play App Signing get their package names claimed automatically, and all you have to do is confirm your status on the developer verification page. The new cost is time, and the review cycle is unchanged.</p>
<p>Now the sideload path. When users download your APK in a browser and install it directly, after September 30, 2026 they will have to clear an identity check in four countries: the package name has to be registered, and the package has to be signed with your private key.</p>
<p>The team left an exit. Development installs through the Android Debug Bridge are unaffected, the advanced flow lets users grant a one-time pass, and a free limited distribution account covers 20 devices. The catch: once the advanced flow is off, updates to unregistered apps fail. Those builds you hand to QA have to fit inside those 20 devices.</p>
<p>Then the enterprise internal distribution path. Managed devices installing from an organization store get an exemption, as long as the device is genuinely managed. If the same app also ends up on employees&rsquo; own unmanaged phones, register it anyway. What this means for cross-platform teams is that internal test builds and demo builds still count as package names and identities — you cannot skate past it with &ldquo;it&rsquo;s only internal.&rdquo;</p>
<h2 id="why-the-math-is-messier-for-cross-platform-teams">Why the math is messier for cross-platform teams</h2>
<p>The first reason is the number of package names. A KMP or Flutter project often produces several artifacts out of one repo: the main build, assorted flavors, test builds, each with its own package name. Verification works off package name and signing key, so your inventory has to cover every artifact and every key, not just the one that ships to the store.</p>
<p>The second is where the keys come from. On one team you can easily have a keystore generated on a CI machine, a keystore someone keeps locally, and the one Play App Signing hosts. The more names there are, the easier it gets to ship a build that was not signed with the key you thought.</p>
<p>The third is what you submit. In the end this verification asks for two things: a package name, and an APK signed with your private key. The first gets checked for duplicates, the second has to prove itself.</p>
<p>While we are on boundaries: this verification only governs package names on Android-certified devices. If the same project also ships to HarmonyOS or iOS, those signing materials are a separate system and outside these rules. But archiving your keys and being able to run your own check is something both sides should be doing.</p>
<h2 id="first-archive-the-keys-and-be-able-to-prove-it">First: archive the keys, and be able to prove it</h2>
<p>Registration requires proving the package name is yours, and the credential they accept is an APK signed with your private key. In other words, the signing key graduates from something sitting in a build cache into an identity document. The official FAQ has a line specifically about this: lose the key and you cannot register the package name, so use a key management solution.</p>
<p>Archiving is not enough by itself. You have to be able to prove it at any time. I wrote a thirty-line script that, in one run, prints an APK&rsquo;s package name and certificate fingerprint and compares them against the archived fingerprint list. Same code, same package name, signed with a different key, and the output forks:</p>
<p><img loading="lazy" src="/images/android-distro-cost/terminal.png"></p>
<p>Identical package name, completely different fingerprint. That is what using the wrong key looks like. This happens on teams more often than you would guess, especially after a CI machine gets replaced or someone regenerates a keystore.</p>
<p>Three archiving rules. Keep the keystore file, the alias, and the fingerprint list together, in a password manager or the team vault; keep the fingerprint list as plain text, one SHA-256 per line, so machines can diff it; wire that step into the release process as a gate, and block the release when it does not match. The official docs also mention that one package name can register multiple signing keys, which is what you want when rotating keys.</p>
<h2 id="second-check-whether-the-package-name-is-taken-before-you-ship">Second: check whether the package name is taken before you ship</h2>
<p>Package names are claimed first come, first served. You check for collisions when you pick the name, not on launch day.</p>
<p>Google opened the Android Developer ID Status API specifically for this, and it returns three states: registered, unregistered, and registered but tied to a different certificate fingerprint. That last one is the painful case, because it means someone else holds the package name.</p>
<p>When you do collide, the official path is to apply for registration, but it needs extra review, and the docs say outright that the package name may be in use by other developers at the same time. Anyone who has done Android knows what two apps sharing a package name means.</p>
<p>The API has a quota, 1,000 calls per project per day, and it has to be attached to a Google Cloud project: create the project, enable the API, set up auth. I do not have that setup on this machine, so this section follows the docs only — I never actually issued a request. For day-to-day status checks, the package name lists in Play Console and the Android Developer Console show it directly, as registered, unregistered, or draft.</p>
<h2 id="third-accounts-and-paperwork-start-what-you-can-start">Third: accounts and paperwork, start what you can start</h2>
<p>For an individual developer, this step is just identity verification. Organizations need two more things: a D-U-N-S number, and a company site verified through Search Console.</p>
<p>D-U-N-S is free, you apply on the Dun &amp; Bradstreet site, and the process takes up to 28 days. It is the only item on the whole list whose waiting time you cannot compress, and the official help docs specifically warn about third-party services charging steep fees for it.</p>
<p>On cost: a full distribution account is a one-time $25, the same ballpark as Play&rsquo;s registration fee; limited distribution is free. Money and forms are not the real problem. The real cost is those 28 days up front.</p>
<h2 id="three-traps-that-will-stop-you">Three traps that will stop you</h2>
<p>The first is losing the key. This is not an inconvenience, it is an inability to register the package name — meaning you never get that name back.</p>
<p>The second is someone else registering the package name first. After you apply you may end up sharing it, which is a landmine with an unknown detonation date.</p>
<p>The third hides on the limited distribution path. Once the advanced flow is off, updates to unregistered apps fail. The official FAQ is explicit: unregistered apps can only be installed and updated through the advanced flow or the Android Debug Bridge. In the 20-device scenario, remember not to flip that switch off.</p>
<h2 id="what-to-do-now-what-can-wait">What to do now, what can wait</h2>
<p>Already in effect: four countries, seven participating stores (Google Play, Samsung Galaxy Store, Xiaomi GetApps among them), covering certified devices on Android 7 and up, with the first phase limited to phones and tablets as form factors.</p>
<p>Three things you can do right now: archive your keys and hook up the self-check, check whether your package names are taken, and get the D-U-N-S and account paperwork moving.</p>
<p>What can wait: stores not on the list, and direct sideloading by users, are unregulated until this round expands. The official timeline is a global rollout in 2027 and beyond, and they recommend developers complete verification before that; press coverage puts the early pace at the US and UK first. Apps already on Play have to register for all form factors — enforcement just starts with phones and tablets.</p>
<p>One phrase worth remembering: the official FAQ says &ldquo;not applicable for now,&rdquo; not &ldquo;never.&rdquo; The gap between those two sentences is that 2027 slot.</p>
<h2 id="last-thing">Last thing</h2>
<p>Add up the three bills and the most expensive item is not the $25. It is the lead time on identity paperwork, and the fact that a signing key has no substitute. Ten minutes to fill in a form, 28 days for D-U-N-S, and if the key is gone there is no second one. So for a cross-platform team this should not be something you remember the week before launch. It belongs as a step in the release process.</p>
<p>Which path does your project take? And can you find that signing key right now? Talk in the comments.</p>
<p>References:</p>
<ul>
<li>Android developer verification official guide <a href="https://developer.android.com/developer-verification/guides">https://developer.android.com/developer-verification/guides</a></li>
<li>Official FAQ <a href="https://developer.android.com/developer-verification/guides/faq">https://developer.android.com/developer-verification/guides/faq</a></li>
<li>Check package name registration status (Developer ID Status API) <a href="https://developer.android.com/developer-verification/guides/check-registration-status">https://developer.android.com/developer-verification/guides/check-registration-status</a></li>
<li>Register a package name with the Console API <a href="https://developer.android.com/developer-verification/guides/developer-console-api">https://developer.android.com/developer-verification/guides/developer-console-api</a></li>
</ul>
]]></content:encoded></item><item><title>Android Sideloading Only Got Half Apple-ified: It Wants Identity, Not Content Review</title><link>http://mings.in/en/posts/android-verify/</link><pubDate>Thu, 08 Oct 2026 08:14:49 +0800</pubDate><guid>http://mings.in/en/posts/android-verify/</guid><description>If you have friends in Brazil, Indonesia, Singapore or Thailand, after September 30 they may run into something new: tap install in some app store, get a prompt saying the developer isn&amp;rsquo;t verified, and it won&amp;rsquo;t install. At the same moment, the China-market Android phone in your hand installs anything with no change at all.</description><content:encoded><![CDATA[<p>If you have friends in Brazil, Indonesia, Singapore or Thailand, after September 30 they may run into something new: tap install in some app store, get a prompt saying the developer isn&rsquo;t verified, and it won&rsquo;t install. At the same moment, the China-market Android phone in your hand installs anything with no change at all.</p>
<p>The Chinese tech scene hasn&rsquo;t talked about this much. The English community has been arguing for a while. The Hacker News thread from October 1 pulled 338 points and 141 comments. F-Droid, on the free software side, put out an open letter together with the Electronic Frontier Foundation, and the title is one line: opposing Android developer verification.</p>
<p>So this is worth taking apart. What it changed, and who actually gets hurt.</p>
<h2 id="in-googles-own-words-apps-have-to-be-registered-by-verified-developers">In Google&rsquo;s own words: apps have to be registered by verified developers</h2>
<p>Google puts it plainly. The <a href="https://developer.android.com/developer-verification/guides">official guide</a> opens with: Android requires all apps to be registered by verified developers before users can install them on certified Android devices.</p>
<p>Let&rsquo;s draw the boundaries first:</p>
<ul>
<li>Takes effect September 30, starting in Brazil, Indonesia, Singapore and Thailand</li>
<li>Covers seven stores: Google Play, HONOR App Market, OPPO App Market, Samsung Galaxy Store, Transsion Palm Store, vivo App Store, Xiaomi GetApps</li>
<li>Applies to certified devices on Android 7 and up, with the check delivered through Google Play services</li>
<li>This round only covers phones and tablets</li>
<li>Global rollout in 2027, with verification extended to all third-party Android stores</li>
</ul>
<p>One detail matters more than it looks: this round only covers those seven stores. The official FAQ is explicit — if you distribute through other channels, or users just sideload, these new requirements don&rsquo;t touch you for now.</p>
<p>In other words, the sideloading road isn&rsquo;t blocked. There&rsquo;s just an ID check at the entrance.</p>
<p><img loading="lazy" src="/images/android-verify/timeline.png"></p>
<p>Google&rsquo;s own analogy is refreshingly candid. They say it&rsquo;s like checking ID at the airport, which is a different thing from security screening. What&rsquo;s being confirmed is who the developer is. The app&rsquo;s content isn&rsquo;t reviewed, and neither is where it came from.</p>
<h2 id="three-roads-pick-one">Three roads, pick one</h2>
<p>The official docs give three paths. The difference sits in the identity verification column.</p>
<table>
	<thead>
			<tr>
					<th></th>
					<th>Full distribution</th>
					<th>Limited distribution</th>
					<th>Sideloading unregistered apps</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Who it&rsquo;s for</td>
					<td>Organizations and professional developers</td>
					<td>Students, hobbyists, individuals</td>
					<td>Developers who won&rsquo;t verify</td>
			</tr>
			<tr>
					<td>Identity verification</td>
					<td>Required</td>
					<td>Not required</td>
					<td>Not required</td>
			</tr>
			<tr>
					<td>Distribution scope</td>
					<td>Any store or your own site</td>
					<td>Up to 20 devices</td>
					<td>Any channel, but users must enable advanced flow</td>
			</tr>
			<tr>
					<td>User experience</td>
					<td>Same as today</td>
					<td>Install after accepting an invite</td>
					<td>Set up once, then install freely</td>
			</tr>
	</tbody>
</table>
<p>Full distribution means handing over identity: a developer console account at $25 one time, a D-U-N-S number if you register as an organization, up to 28 days for review, plus a website verified with Google Search Console.</p>
<p>Limited distribution is the door left open for people who don&rsquo;t want to hand over a government ID. Free, no cap on app count, but limited to 20 devices and users have to accept your invite. Students, hobbyists, and people writing apps for themselves take this road, it&rsquo;s the least hassle.</p>
<p>The third road is for users: apps from unregistered developers still install, but the user has to go through advanced flow setup once. Google says the point of those safeguards is to give users time to break off coercion.</p>
<p>One official line to note: once advanced flow is turned off, updates to unregistered apps fail. That road works as a destination, not as a daily driver.</p>
<h2 id="i-built-an-apk-by-hand-what-gets-verified-is-really-just-two-things">I built an APK by hand. What gets verified is really just two things</h2>
<p>Concepts go further if you run them yourself. My local Android SDK had aapt2, d8, zipalign, apksigner and keytool, enough to hand-assemble an APK without Android Studio.</p>
<p>The flow: write an AndroidManifest.xml with just the package name com.example.handmade, javac one class, d8 it into classes.dex, aapt2 link to produce the APK, then generate an RSA key pair on the spot with keytool and sign with apksigner.</p>
<p>Then pull the identity out and look at it:</p>
<pre tabindex="0"><code>Signer #1 certificate DN: CN=Handmade Identity Demo, O=none, C=CN
Signer #1 certificate SHA-256 digest:
0a220aaa9b719f34f97e88cb46a95de020fba812fee540251cc2cae7a188a269
Verified using v2 scheme (APK Signature Scheme v2): true

package: name=&#39;com.example.handmade&#39; versionCode=&#39;1&#39; versionName=&#39;1.0&#39;
</code></pre><p>An 8,619-byte APK, and the identity is those two lines: the package name com.example.handmade, plus the certificate fingerprint, that SHA-256 starting with 0a22. That pair is what Google wants you to register. Officially: provide an APK signed with your private key, which links that APK to your developer account.</p>
<p><img loading="lazy" src="/images/android-verify/terminal.png"></p>
<p>A control test makes it more interesting.</p>
<p>I verified the unsigned APK and it flatly reported DOES NOT VERIFY, missing META-INF/MANIFEST.MF. Then I signed the same APK with a second key. Not a character of code changed, the package name didn&rsquo;t change, and the fingerprint went from starting 0a22 to starting ee56.</p>
<p>So what gets verified is the person, not the code. Which explains why the official FAQ has a line specifically saying that if you lose your signing key you can&rsquo;t register the package name. That keystore file isn&rsquo;t a build cache, it&rsquo;s an ID card. Archive it like private data.</p>
<h2 id="this-isnt-app-store-ification-its-macos-notarization">This isn&rsquo;t App Store-ification, it&rsquo;s macOS notarization</h2>
<p>Most people&rsquo;s first reaction is that Google is going Apple. That read is only half right.</p>
<p>Where it&rsquo;s similar is real: distribution hangs off an account. On Apple&rsquo;s side every install path hangs off the Apple Developer Program, $99 a year, and organizations also need a D-U-N-S. On macOS it&rsquo;s more direct — Gatekeeper checks a notarization ticket online on first run. And the third-party marketplaces Apple opened up in the EU also require confirming at install time that the source is an authorized channel.</p>
<p>Where it&rsquo;s not similar is the point, and there are two places.</p>
<p>First, Google doesn&rsquo;t review content. The official help doc says outright that app content and functionality information is not collected. Apple&rsquo;s setup is review plus cut: content rules up and down, and under the newest EU terms it&rsquo;s 26% for in-app purchase, 20% for alternative payments, 15% for link-outs, and another 5% for third-party marketplaces or web distribution.</p>
<p>Second, Google left a no-identity exit: 20-device limited distribution, advanced flow, and adb development installs that are completely untouched. Apple has no counterpart.</p>
<p>There&rsquo;s also a fun contrast in direction. In the EU, Apple is being pushed open by the Digital Markets Act. Google here is voluntarily tightening. Nobody is copying anybody — two curves pointing opposite ways, meeting in the middle.</p>
<p>The line actually worth watching is the one about verification extending to all third-party Android stores. At that point Google isn&rsquo;t just the doorman of its own yard, it&rsquo;s the identity issuer for other people&rsquo;s stores.</p>
<h2 id="who-gets-hurt">Who gets hurt</h2>
<p>Ordinary users won&rsquo;t. The experience genuinely doesn&rsquo;t change, which is the hardest thing for opponents to argue.</p>
<p>Three other groups will. Non-profit repos like F-Droid are first in line, and their open letter is blunt:</p>
<blockquote>
<p>Installing or launching any app on a certified device will phone home to Google to verify that the developer and app have been approved.</p>
</blockquote>
<p>They host thousands of apps, verification binds to package name, which means every volunteer has to hand their identity to Google. Their conclusion is to advise developers not to register.</p>
<p>The second group is people who can&rsquo;t complete verification. The official FAQ admits it: developers in sanctioned regions cannot complete verification. Offline environments, no documents to produce, or a region where the flow simply doesn&rsquo;t work — those people are shut out of distribution.</p>
<p>The third group is any future distributor that wants to compete with Play. They can&rsquo;t even go live without going through Google&rsquo;s registration process first.</p>
<h2 id="for-developers-in-china-three-practical-moves">For developers in China, three practical moves</h2>
<p>First, if your app is Play-only and you use Play App Signing, you&rsquo;re already inside this flow. Google claims it automatically, no extra action needed. To check your status, just look at the developer verification page in Play Console.</p>
<p>Second, if you have overseas users and distribute outside Play, what you should do now is archive your signing keys properly, apply for the D-U-N-S early, and treat 2027 as the real deadline instead of staring at this September.</p>
<p>Third, for apps you only write for yourself or a small circle, adb is officially kept and advanced flow works too — but remember that updates to unregistered apps depend on it, so don&rsquo;t turn it off.</p>
<p>One API worth knowing about: Google opened the Android Developer ID Status API, which tells you whether a package name is registered, 1,000 calls a day. It has to be attached to a Google Cloud project to call, which I don&rsquo;t have here, so I&rsquo;m only noting it as a lead. For people who distribute, it means you can ask who owns a package name before installing.</p>
<h2 id="last">Last</h2>
<p>This isn&rsquo;t a security check. It&rsquo;s the gatekeeping right of distribution moving out of the operating system and into Google&rsquo;s account system. Nearly invisible to ordinary users, a structural blow to non-mainstream distribution.</p>
<p>The 2027 global rollout is the watershed. These four countries today are just a very cheap pilot that can be adjusted at any time.</p>
<p>If you&rsquo;ve got an app that only distributes inside China, will you register, or wait for 2027? Talk it out in the comments.</p>
<p>References:</p>
<ul>
<li>Android developer verification official guide <a href="https://developer.android.com/developer-verification/guides">https://developer.android.com/developer-verification/guides</a></li>
<li>Official FAQ <a href="https://developer.android.com/developer-verification/guides/faq">https://developer.android.com/developer-verification/guides/faq</a></li>
<li>F-Droid open letter <a href="https://f-droid.org/en/2026/02/24/open-letter-opposing-developer-verification.html">https://f-droid.org/en/2026/02/24/open-letter-opposing-developer-verification.html</a></li>
<li>Hacker News discussion <a href="https://news.ycombinator.com/item?id=49917761">https://news.ycombinator.com/item?id=49917761</a></li>
</ul>
]]></content:encoded></item><item><title>Flutter 1.7.8 Stable Released</title><link>http://mings.in/en/posts/flutter-1-7-8/</link><pubDate>Tue, 09 Jul 2019 09:00:00 +0800</pubDate><guid>http://mings.in/en/posts/flutter-1-7-8/</guid><description>Flutter 1.7.8 stable is out, fixing a batch of bugs.</description><content:encoded><![CDATA[<p>The latest stable Flutter 1.7.8 is out, and the headline fix is <a href="https://github.com/flutter/flutter/issues/18494">the bug that kept a single APK from supporting both 32-bit and 64-bit</a>. No more of that hack to package for the domestic market. Lovely.</p>
<p>A partial list of the other fixes:</p>
<h3 id="v176">v1.7.6</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/pull/34684">#34684</a> The return type of the almost never used <code>ParentDataWidget.debugDescribeInvalidAncestorChain</code> method is now <code>Iterable&lt;DiagnosticsNode&gt;</code> instead of <code>String</code>. Existing uses can call <code>.join('\\n')</code> on the return value if they need to continue to use a <code>String</code> instead of a <code>DiagnosticsNode</code>.</li>
</ul>
<h3 id="v174">v1.7.4</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/pull/30069">#30069</a> Text inline widgets allows embedding arbitrary widgets inline with text. <code>TextSpan</code>has also been reworked to inherit from <code>InlineSpan</code>, in order to support <code>WidgetSpan</code>, which is used to define inline widgets. Existing uses of <code>TextSpan</code> should not assume the object is of type <code>TextSpan</code> anymore.</li>
</ul>
<h3 id="v171">v1.7.1</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/issues/33480">#33480</a> The <code>FadeInImage</code> widget no longer supports the <code>placeholderSemanticLabel</code>property.</li>
</ul>
<h3 id="v167">v1.6.7</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/issues/32374">#32374</a> The <code>Image</code> widget now supports two new properties: <code>frameBuilder</code>, and <code>loadingBuilder</code>, which enable callers to easily add a placeholder image which the image ios loading, add effects to the image once it loads (such as fading it in), and monitor the loading progress of the image (e.g. to show the user a loading indicator).</li>
</ul>
<h3 id="v163">v1.6.3</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/pull/33148">#33148</a> ExpandIcon now uses Colors.white60 instead of Colors.white54 when dark theme is used (ThemeData.brightness is set to Brightness.dark).</li>
</ul>
<h3 id="v162">v1.6.2</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/pull/32936">#32936</a> cleaned up the <code>ImageStream</code> listener API. <code>addListener()</code> and <code>removeListener()</code>now take an instance of <code>ImageStreamListener</code>, which contains references to the individual callbacks. See <a href="https://groups.google.com/forum/#!topic/flutter-announce/NWTszrEq9U0">the announcement</a> for more information.</li>
</ul>
<h3 id="v161">v1.6.1</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/pull/32528">#32528</a> Tapping a modal bottom sheet no longer dismisses it by default.</li>
</ul>
<h3 id="v160">v1.6.0</h3>
<ul>
<li><a href="https://github.com/flutter/flutter/pull/30983">#30983</a> To support structured error messages <a href="https://github.com/flutter/flutter/issues/27327">#27327</a> the signature of InformationCollector and the context parameter of the FlutterErrorDetails constructor were changed. This should not impact you unless your package is attempting behave like part of the Flutter framework. See <a href="https://github.com/flutter/flutter/issues/31962#issuecomment-488882515">this comment</a> which discusses how to write code that is forwards and backwards compatible with this change.</li>
<li><a href="https://github.com/flutter/flutter/pull/31569">framework #31569</a>/<a href="https://github.com/flutter/engine/pull/8695">engine #8695</a> Rect and RRect are now const constructable and are backed by 64 bit doubles rather than 32 bit floats internally.</li>
<li><a href="https://github.com/flutter/flutter/pull/31917">framework #31917</a> &lt;- <a href="https://github.com/flutter/engine/pull/8796">engine #8796</a> &lt;- <a href="https://github.com/dart-lang/sdk/commit/1dd0f88c84">dart 1dd0f88c84</a> Fixes bug in StreamIterator which allowed constructor argument to be null. Also allowed await for on a null stream. This is now a runtime error.</li>
<li><a href="https://github.com/flutter/flutter/pull/30884">#30884</a> <code>TabController.animationController</code> changed to be <code>unbounded</code> to allow <code>DefaultTabController</code> to handle changes to number of tabs (after initial build).</li>
</ul>
<h3></h3>
]]></content:encoded></item></channel></rss>