The issue with enadling Ad Review feature from AppLovin

Hi there!

While working on the app, we need to enable the “Ad Review” feature from AppLovin, as explained here: https://support.applovin.com/hc/en-us/articles/13883454177421

To do this, just follow two simple steps:

  1. Additions to root-level build.gradle file:
buildscript {
  repositories {
    maven { url 'https://artifacts.applovin.com/android' }
  }
  dependencies {
    classpath "com.applovin.quality:AppLovinQualityServiceGradlePlugin:+"
  }
}
  1. Additions to app-level build.gradle file:
apply plugin: 'applovin-quality-service'
applovin {
  apiKey "ad-review-key"
}

In the test application built in Android Studio, everything works as expected (AppLovin provides a Mediation Debugger which displays debug information). Defold doesn’t distinguish between root-level and app-level build.gradle files. We can only use the build.gradle files of native plugins to add dependencies. It’s not possible to add a buildscript section to these files. (AFAIK)

I created a Docker image of the Extender to examine how the build server operates “under the hood”. It turns out there’s a single build.gradle file (from /extender/server/docker-base/template.build.gradle) to which build.gradle files from all the plugins are applied during the server’s operation (apply from ).

In Android Studio, I followed a similar approach (consolidated everything into a single root-level build.gradle) and successfully built the test application. Then, I modified the mentioned template.build.gradle, built the Extender, and used it to build the production application (not a test one). During the build process, no errors occurred. Information about the plugin appeared, similar to when building a test application in Android Studio. After the app build was completed, APK files were generated. However, according to the information from the Mediation Debugger, the final application doesn’t include the required plugin.

Based on the above, there are two questions:

  1. Is it possible to enable this functionality without using our own Extender?

  2. If not, and we need to use our own Extender, are there any specific considerations for adding such plugins?

P.S. If needed, I can show the build.gradle files that were generated for the test application and the production one.

Thank you!

11 Likes

We only use Gradle for resolving dependencies. We do not use it to build or otherwise influence the build pipeline in any way. I’m trying to understand what com.applovin.quality:AppLovinQualityServiceGradlePlugin actually does and at what step of the build process it interacts witj.

Hi Bjorn!

From what we know so far com.applovin.quality:AppLovinQualityServiceGradlePlugin does the following:

  1. During the configuration phase of gradle it uploads its dependencies to the .safedk folder
  2. It then embeds itself into the standard Android build pipplane as two custom tasks:

Task :preBuild UP-TO-DATE
Task :preDebugBuild UP-TO-DATE
Task :mergeDebugNativeDebugMetadata NO-SOURCE
Task :generateDebugBuildConfig
Task :javaPreCompileDebug
Task :checkDebugAarMetadata
Task :generateDebugResValues
Task :mapDebugSourceSetPaths
Task :generateDebugResources
Task :createDebugCompatibleScreenManifests
Task :extractDeepLinksDebug
Task :processDebugMainManifest
Task :processDebugManifest
Task :mergeDebugShaders
Task :compileDebugShaders NO-SOURCE
Task :generateDebugAssets UP-TO-DATE
Task :mergeDebugAssets
Task :compressDebugAssets
Task :processDebugJavaRes NO-SOURCE
Task :mergeDebugResources
Task :mergeDebugJniLibFolders
Task :checkDebugDuplicateClasses
Task :mergeDebugNativeLibs NO-SOURCE
Task :stripDebugDebugSymbols NO-SOURCE
Task :validateSigningDebug
Task :writeDebugAppMetadata
Task :mergeLibDexDebug
Task :writeDebugSigningConfigVersions
Task :desugarDebugFileDependencies
Task :processDebugManifestForPackage
Task :mergeDebugJavaResource
Task :processDebugResources
Task :compileDebugJavaWithJavac
Task :dexBuilderDebug
Task :mergeProjectDexDebug
Task :mergeExtDexDebug
> Task :safedkAdjustInputsDebug
> Task :safedkInstrumentationDebug
Task :packageDebug
Task :createDebugApkListingFileRedirect
Task :assembleDebug

  1. what exactly these tasks do is hard to understand. I’ve contacted Applovin’s technical team, but so far they’ve been very reluctant to respond. As far as I understand this safedk somehow protects dex’s

Translated with www.DeepL.com/Translator (free version)

2 Likes

I see. Ideally there is a way to run the code in the Gradle plugin in isolation so that those additional steps can be applied to a build made with Defold. It is not really realistic for us to also migrate the Android build process to use Gradle, at least I don’t think it is!

For this we need at least possibility to inject code into template.build.gradle directly. Because gradly buildscript command only works from root gradle and does not work when subscript is included with “apply from:”

I think to solve this issue we need:

  1. Some way to inject code to template.build.gradle directly
  2. Task doWorkAfterDefoldBuild

Then we can write hooks in extensions’s gradles which will anchor custom gradle tasks after Defold’s custom build pipline

As mentioned, we don’t really use Gradle.
Our pipeline is simply built differently.

We have other apis (or could add one) for hooking up to the Activity if that’s something that you need.

But it seems like you also need some post processing of the bundle?
What does it do, and what tools are actually needed to do it? (I mean, not gradle, but the actual command line tools)

Hi, Björn!

Currently, it’s not entirely clear how to execute these tasks in isolation. The “applovin-quality-service” plugin source code is not available. Also, considering that the Defold project structure and the typical Android project structure do not match either before or after the build (I’m not referring to the final APK, of course).

In the Gradle log, it can be seen how tasks are integrated into the Android Gradle Plugin build tasks (for debug) and what they depend on. Essentially, this occurs in the final stages of the build, after the DEX files are ready and before the APK is assembled.

[SafeDK-DEBUG] Task safedkInstrumentationDebug created
[SafeDK-DEBUG] Task safedkAdjustInputsDebug created
[SafeDK-DEBUG] Dependencies: safedkAdjustInputsDebug depends on mergeExtDexDebug
[SafeDK-DEBUG] Dependencies: safedkAdjustInputsDebug depends on mergeLibDexDebug
[SafeDK-DEBUG] Dependencies: safedkAdjustInputsDebug depends on mergeProjectDexDebug
[SafeDK-DEBUG] Dependencies: safedkInstrumentationDebug depends on safedkAdjustInputsDebug
[SafeDK-DEBUG] Dependencies: safedkInstrumentationDebug depends on mergeDebugJniLibFolders
[SafeDK-DEBUG] Dependencies: packageDebug depends on safedkAdjustInputsDebug
[SafeDK-DEBUG] Dependencies: packageDebug depends on safedkInstrumentationDebug
[SafeDK-DEBUG] Dependencies: buildDebugPreBundle depends on safedkAdjustInputsDebug
[SafeDK-DEBUG] Dependencies: buildDebugPreBundle depends on safedkInstrumentationDebug

The artifacts folder in build/intermediates/safedk looks like this after the APK is built.

├── analysis
│   └── debug
│       ├── AndroidManifest.xml
│       └── app_output.json
├── dex
│   └── debug
│       └── classes.dex
└── properties
    ├── debug
    │   ├── applovin-quality-service.properties
    │   └── build_info.json
    └── release

Then the plugin performs some manipulations with the manifest and dex files. There’s actually more to the plugin operation log, I’ve just highlighted what I think is important.

[SafeDK-DEBUG] dexDirsAndFiles=[build/intermediates/dex/debug/mergeExtDexDebug, build/intermediates/dex/debug/mergeProjectDexDebug, build/intermediates/dex/debug/mergeLibDexDebug]
...
[SafeDK-DEBUG] __dexFolders__ field found - override it
[SafeDK-DEBUG] manifest files for processing: [build/intermediates/merged_manifests/debug/AndroidManifest.xml]
[SafeDK-DEBUG] java -cp AppLovinQualityServiceGradlePlugin-5.0.3.jar com.safedk.appwrapper.AppWrapper "--full-dex" "build/intermediates/safedk/properties/debug/applovin-quality-service.properties"
...
[SafeDK-DEBUG] DexLibApi: 23, Dex file path: .safedk/dex/android-support-multidex.dex
[SafeDK-DEBUG] DexLibApi: 23, Dex file path: build/intermediates/dex/debug/mergeExtDexDebug/classes.dex
[SafeDK-DEBUG] Set DexLibApi for output: 23 based on: build/intermediates/dex/debug/mergeExtDexDebug/classes.dex
...
[SafeDK-DEBUG] DexLibApi: 23, Dex file path: .safedk/dex/SafeDKAndroid-6.0.3.dex
[SafeDK-DEBUG] Dependency class was not found: com.fyber.inneractive.sdk.external.ImpressionData
[SafeDK-DEBUG] Removing discovery class for undetected SDK com.inneractive
...
[SafeDK-DEBUG] Total: Methods: 56255, Fields: 39667, Strings: 16072, Types: 5407
...

I would appreciate any ideas on how and in which direction I can investigate and explore alternative solutions.

Currently, I am manually attempting to transform our Defold project into a standard Android project, aiming to build it through the “gradle build” with the standard Android Gradle Plugin.

Yes, I realize that Defold has its own assembly pipeline.

But at least Defold uses the following gradle features:

  1. calls the configuration stage

  2. calls its own downloadDependencies task

My idea is to add one more empty custom task doAfterBuild, which will be called after Defold custom build, just like downloadDependencies is called before the build.

And the code that will be injected into gradle by the gradle action will hang the dependency on the doAfterBuild task. And it will be executed at the stage of configuration.

Why I’m talking about gradle - because we don’t have command utilities. Now the problem is that we can’t make one of Applovin’s options work, which uses custom gradle steps. And what’s more it’s a black box.

I realize that the problem is also that the files are arranged differently than in the standard build, but this can be solved by writing a file rearrangement directly in gradle.

Why I think this is the right solution. First of all, you won’t need to rewrite Extender. In the future there may be a thirdparty that will require execution of custom steps by gradle

1 Like

Our publisher would also like us to move to AppLovin after some recent problems with Unity Ads, but it seems pointless without Ad Review. I’m going to explore other options, maybe Ironsource mediation.

As an aside, it amazes me that AppLovin can serve inappropriate ads, and then make devs install an extra SDK to avoid them, and write a blog post like this is some kind of benefit!

3 Likes

Note that on the extender server we resolve dependencies (using Gradle), build the engine (using our own build pipeline) and gather up resources from dependencies. The engine, Android resources, dex files and so on are then sent back to the client:

The process of actually creating an APK/ABB file is done in bob.jar on the client in AndroidBundler.java:

So what you really need is to somehow figure out a way to optionally hook in and use gradle and the AppLovin plugin here on the client/host, not on the extender. This is probably doable, but it will for sure require some work.

1 Like

Interesting idea. I’m going to go look at bob’s source code

1 Like

Nowadays we have more “hooks” into Bob.jar, that allows for a custom .jar file to add functionality to it.

These .jar files are loaded if they’re located in the correct extension folder : /plugins/share
example from spine
(source for that jar file is found here, and the build script is found here)

The .jar file is loaded by Project.java here.

I think one option would be to add a custom step to the AndroidBundler, that allows for running a custom tool on the package folder.

One major drawback for this setup is that the user would have to have the required tools installed (e,g, gradle and potential SDKS), unless the extension can bring those files.
I’d prefer if the extension’s plugin would contain any tools needed.