Skip to content

Build1 publisher2 min readPublished

Unity's build pipeline downgrades AdMob's build-stopping error to a log line

Leaving the AdMob App ID field empty in Unity 6000.4.0f1 still produced an installable APK, because the exception the plugin throws to stop the build is caught by Unity's own pipeline and written to the log.

The Engineer · Build desk

What happened

  • A release APK built in Unity 6000.4.0f1 with the AdMob App ID field left empty came out at 19,627,503 bytes and installs, launches and dies before Unity draws a single frame.
  • The plugin's guard did fire: the build report carries a Preprocess Player entry reading BuildMethodException: [GoogleMobileAds] Android Google Mobile Ads app ID is empty.
  • The same report line recorded result=Succeeded alongside errors=1, warnings=0 and seconds=151.1 for the run.
  • Running aapt2 against the finished APK's AndroidManifest.xml returned zero matches for com.google.android.gms.ads.APPLICATION_ID.
  • The class comment in AndroidBuildPreProcessor.cs lists throwing on an unset Android App ID as its second job, and the check that does it is in ManifestProcessor.cs.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • exposure A release gate that reads the process exit status alone cannot tell this run from a clean one, so the first place the missing App ID becomes visible is a device.
  • constraint A plugin author on this Unity version cannot make a build fail from inside a build-report pre-processor, so any hard requirement has to be enforced by the project's pipeline instead of by the package.
  • decision Validating the App ID is the project's job, because the plugin only tests for an empty string and a mistyped ID passes untouched.

The ordering comes out of two numbers in the plugin's own editor scripts. AndroidBuildPreProcessor, which writes the Gradle templates, has callbackOrder -1. ManifestProcessor, which holds the App ID test, has callbackOrder 0 [9]. Unity runs the lower number first, so the build resolves every Android dependency, downloads play-services-ads and writes the templates before anything reads the text box [10].

What gets resolved is in the package's own XML. GoogleMobileAdsDependencies.xml pins play-services-ads 25.4.0, constraintlayout 2.1.4, lifecycle-process 2.6.2 and fragment 1.7.1 [11]. GoogleUmpDependencies.xml adds user-messaging-platform 4.0.0 [12]. The External Dependency Manager bundled with the package is 1.2.188 [13]. A newer ads library is in there too, ads-mobile-sdk 1.4.0, which the source calls NextGen; it is off by default, and switching to it raises the minimum API level from 23 to 24 [14].

The guard itself is a string test. ManifestProcessor trims GoogleMobileAdsAndroidAppId and calls StopBuildWithMessage when the trimmed length is zero [15]. That method throws, and Unity's stack trace shows where the throw lands: Editor/Mono/BuildPipeline/BuildPipelineInterfaces.cs, where line 505 logs the exception and line 492 carries on [16]. The APK that reached disk is 19.6 MB [5], with MobileAdsInitProvider, AdActivity and AdService all merged into its manifest [21].

For this to be your failure too, your Unity version has to treat a pre-processor exception the way this one did. The run used Unity 6000.4.0f1 Personal on macOS 26.5.1 [2], with the plugin build published four days earlier [3]. Line 492 is a line number in that version's source [16].

One more mechanism for anyone driving Unity from CI. AssetDatabase.ImportPackage(pkg, false) returned immediately and imported nothing: the done line was logged, the process exited 0, and Assets/ was left exactly as it was [22]. ImportPackage is asynchronous, and -quit tears the editor down before it runs [23]. The -importPackage command-line argument is synchronous and does the import [24].

What to watch

  • Whether the next GoogleMobileAds release moves the App ID test to a lower callbackOrder or out of the build callbacks entirely.
  • Whether Unity changes BuildPipelineInterfaces so an exception from a build-report pre-processor fails the build instead of being logged.
  • Whether the plugin flips its default to ads-mobile-sdk 1.4.0, which would take the minimum API level to 24.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories