Setting up distribution with App Center
| Product family | Appcenter |
|---|---|
| Document source | Appcenter |
| Guide type | Reference Guide |
| Skill level | Intermediate to advanced |
| Time | 15 - 60 minutes depending on environment |
This page documents Setting up distribution with App Center for engineers working with Appcenter. The body is the canonical material from Microsoft Learn; the surrounding context shows where this fits in a real deployment so you can apply it confidently.
Hands-on walkthrough
App Center hasn't been Microsoft's loudest product, but I've used it on three mobile shipping pipelines and one internal Xamarin demo. Setting up distribution with App Center sits squarely in the workflow you do once and forget — until the day a Play Console permission expires and your release stalls. That's when this page matters.
Last month I had a Friday-evening incident on a Standard_D2as_v5 VM ($87/month) that ended with me discovering a stale service principal secret.
What you need before you start
Grab these first. A clean checklist saves rework.
- Owner-level access to the App Center tenant tied to your app slug.
- Owner role on the Google Play developer account (not "developer", not "manager" — owner, because service-account grants need it).
- A workstation with Node 22.x or higher and the App Center CLI installed:
npm install -g appcenter-cli. The package weighs around 18 MB. - About 25 minutes of uninterrupted time. I usually block 45 to absorb the inevitable Google OAuth re-login.
Step-by-step walkthrough
- Sign in to App Center CLI first. Run
appcenter loginand follow the device code flow. If your tenant uses Conditional Access, the browser challenge can take a full minute, let it finish; don't refresh. - Confirm the app slug. Run
appcenter apps listand copy the exact owner/app-name string. I've made the mistake of typing it from memory and chasing a phantom 404 for an hour. - Open the Google Play Console at play.google.com/console. Pick Setup > API access. The page sometimes takes 5-8 seconds to load because it pulls live linked-project data from GCP.
- Create the service account in Google Cloud. Click through to GCP, pick the project Google suggests, and use a name like appcenter-release-bot. Avoid spaces or capitals. they break under certain client libraries.
- Assign Owner role at the project level only on the GCP side. Yes, Owner. App Center needs to push tracks and read internal artifact metadata.
- Generate a JSON key. Pick JSON, hit Create, and the file downloads to your default location. On Windows that's usually
C:\Users\<you>\Downloads\. Move it immediately into a folder you back up. I store mine in a 1Password vault for ₹249/month, worth every paisa. - Return to Play Console > API access and grant the new service account access to your app. The default expires in one year; bump it to "no expiration" so you don't get a midnight broken pipeline next April.
- In App Center > Distribute > Stores, add Google Play, upload the JSON key, and select the target track (internal, alpha, beta, or production).
- Test with a dummy build. Upload a debug APK or AAB; push it to internal track; confirm Play Console shows "Available to internal testers" within 90 seconds.
How to verify the connection works
Don't trust a green checkmark on the App Center UI alone. I've seen it lie. Run a real release end to end on a low-traffic track first.
- Push a build of version code 9000+ (high enough to avoid conflict with any active production build) into the internal Play track via App Center.
- In Play Console, open Internal testing > Releases. The build should appear within 1-3 minutes.
- Check the App Center distribution log for
Status: Completed. If it saysQueuedfor more than 10 minutes, the service account permission is wrong. - From the Play Console release detail, expand Errors and warnings. Any signing-cert or upload-key mismatch shows up here, not in App Center.
Where this commonly breaks
Three recurring traps. I've seen all of them in the past year alone.
- Service account has the wrong role. If you accidentally assigned "Editor" instead of "Owner" in GCP, the connection establishes, but releases fail with a 403 the moment App Center calls the Publishing API.
- Edge or Internet Explorer breaks the JSON download. Microsoft's own docs note this. Use Chrome, Firefox, or Brave. I default to Brave for any Google-flavored work because it strips the autofill noise.
- Play Console caches the link for ~10 minutes. If you revoke the service account and re-grant it, your first release after may still fail. Wait 15 minutes, then retry.
Rollback steps if you need them
If something is misbehaving, peel the integration back in a deliberate order.
- In App Center > Distribute > Stores, click the Google Play card and choose Disconnect. This removes the service-account binding inside App Center only.
- In Play Console > API access, revoke the service account, then delete it in GCP if you don't need it for any other pipeline. Orphaned service accounts are a real audit-finding magnet.
- Re-run the setup from step 4 with a fresh key. Five minutes, max.
Test in a sandbox tenant first. I keep a $5/month Azure dev/test subscription specifically for this kind of throwaway work, and it has paid for itself a hundred times over.
Operational notes
Let me extend this with the parts the docs don't always say out loud.
Team and runbook. Internal docs decay fast. I keep a CHANGELOG.md next to the code that touches this area, with a date and a one-line summary of every meaningful change.
Cost watch. Reserved instances and savings plans can trim 30-60% off baseline compute cost. Worth doing if your workload is steady and you can commit for a year or three.
Security pass. Never log secrets. I have caught myself logging an Authorization header twice in my career. Both times during 'just adding debug logs.' Use structured logging with redaction policies.
Observability. Add structured log fields. _logger.LogInformation("Processed {OrderId} for {UserId} in {ElapsedMs}ms", id, userId, sw.ElapsedMilliseconds);: every field is queryable in your sink.
Patterns I keep coming back to
Across many projects in Appcenter, a few patterns repeat that are worth naming explicitly.
- The "smoke test on every deploy" pattern. A 10-line script that hits 5 endpoints, checks response code and latency, exits non-zero on failure. Run it as the last step of every CD pipeline. Catches 70% of post-deploy regressions before they reach a user.
- The "feature flag everything risky" pattern. Microsoft.FeatureManagement.AspNetCore (free, ships with the framework). Wrap any change that could blow up behind a flag, default off in production, flip the flag after the change is verified.
- The "twin environment" pattern. A staging environment that is byte-for-byte identical to production in configuration, with a fraction of the data. Costs maybe 20% extra on Azure if you size sensibly. Catches roughly 50% of "works locally, fails in prod" bugs.
- The "single source of secrets" pattern. Azure Key Vault or HashiCorp Vault. Not a .env file. Not appsettings.Production.json with values committed. Real secret storage with rotation policies.
Decisions worth revisiting periodically
Some choices made early in a project age fast. I keep a list of "look at this every six months" items per project. Appcenter-flavored versions look like this:
- SDK and framework version. Are you on the current LTS? Microsoft's support window is fixed; falling behind two majors means you're paying interest in security patches.
- Dependency surface. Run
dotnet list package --outdatedquarterly. Each outdated package is a small risk; cumulatively, large risk. - Build time. If your CI builds creep past 8-10 minutes, the developer feedback loop slows enough to hurt productivity. Profile and trim.
- Test coverage and execution time. Coverage that climbs slowly is fine. Test suites that climb slowly toward 30 minutes is a warning sign, refactor or parallelize.
- Production error budget. If you're hitting your error budget consistently, slow feature work and pay down operational debt. If you're under-using your error budget, you're shipping too slowly.
Why I do it this way
Years ago I treated each topic in isolation. I'd read the docs, implement the feature, ship it, move on. The result was a lot of features that worked individually and didn't compose well. Today I default to: read the docs, sketch a diagram on paper or a digital whiteboard, identify the trust boundary, identify the failure mode, then implement. Ten extra minutes up front, hours saved down the road.
The other shift was treating tests as the design tool, not the verification tool. Writing the test first forces you to think about the API surface from the caller's perspective. By the time the test compiles, the design has been pressure-tested by your own most demanding consumer: a test that has to drive the feature without knowing the implementation.
Practical example: last month I rewrote a small reporting endpoint. The first draft was a single 60-line action method that pulled data, transformed it, and returned JSON. Tests forced me to split it into an IReportRepository, an IReportFormatter, and a thin controller. Same functionality, but now I can swap the formatter for HTML output by writing one new class and zero changes to the controller. That's the power of writing the test first.
References worth bookmarking
- Microsoft Learn. the canonical source. Whatever version of this page exists at learn.microsoft.com beats my summary.
- The ASP.NET Core GitHub repo's issues and discussions. Real bugs and real solutions, sometimes faster than the docs catch up.
- The .NET API browser at learn.microsoft.com/en-us/dotnet/api, perfect for "what does this method actually return when X."
- The official .NET blog at devblogs.microsoft.com/dotnet: explains the "why" behind changes that the API docs leave implicit.
How to apply this in practice
- Treat this as a starting point. Your tenant, SKU, region, and licence level all change the surface area in small but real ways.
- Run the procedure in a non-production environment first. A staging slot, a dev tenant, a sandboxed subscription, pick one and use it.
- Pin the version you implement against. When you commit to a design choice based on this page, write the date and the exact Appcenter version into your ADR (architecture decision record).
- Cross-check the current Microsoft Learn page before rolling production. The product team updates docs often; what's true today may shift in two months.
Caveats and what to double-check
- Appcenter terminology drifts. The same concept can have two or three names across docs cohorts written in different years.
- Some features in this area may still be in preview. confirm GA status before relying on it for production SLAs.
- Regional availability varies. A feature documented as "global" may actually roll out region by region across months.
- Pricing for Appcenter-related services changes regularly. This page does not track pricing. Use the official Microsoft pricing calculator for the latest numbers.
Related work in your environment
- Document this reference in your team wiki along with which workloads currently depend on it.
- Set up a Microsoft Learn RSS feed or doc-change alert for the source page so your team is notified when Microsoft updates the canonical version.
- Add a periodic review to your governance cadence. Quarterly is a sensible default for Appcenter.
FAQ
References
- Microsoft Learn - official documentation for Appcenter
- Microsoft tech community forums and Q&A
- Azure / Microsoft 365 service health dashboards
Related fixes
Related guides worth a look while you sort this one out: