5

The context:

I use AdMob mediation to display banner ads in my app. I integrated Millennial ad network SDK and Millennial AdMob adapter.

Problem: my app supports Android API 9+, whereas Millennial SDK supports API 16+. Worse, instead of gracefully failing (returning no ad to the AdMob mediation layer so that it can continue going down the mediation waterfall), the SDK crashes on devices running Android < 16 (Fatal Exception: java.lang.NoSuchMethodError android.webkit.WebSettings.setAllowUniversalAccessFromFileURLs)

Apparently Millennial developers are not planning to fix this, they recommend publishing 2 distinct APKs ("<16" without their SDK and "16+" with their SDK), which is a troublesome solution.

I would prefer a simpler solution: on devices running Android API < 16, I'd like to reproduce what happens when an AdMob adapter is missing: AdMob mediation just goes to the next network. This would mean unloading or erasing the Millennial adapter class before I instantiate the AdMod mediation banner.

The question:

Is there any way to prevent any future instantation of a given class (from a 3rd party library) at runtime? (e.g. by forcing a ClassNotFound exception)

7
  • Do you have a constructor on this class already? If not, implement a default one (with no parameter) that throws your exception. Commented Nov 6, 2015 at 11:45
  • @dotvav Yes the class MillennialAdapter has a constructor, which is called by the AdMob mediation library. I could achieve my purpose by decompiling the adapter class and modifying it, but I'd like to avoid this. Commented Nov 6, 2015 at 11:48
  • Oh then you mean preventing any future instantiation of a class *you don't control*. Commented Nov 6, 2015 at 11:49
  • Its not easier to just check the OS version to not use admob below the minimum sdk? Commented Nov 6, 2015 at 11:49
  • There are a few hints here about Java classes unloading or reloading that may help: stackoverflow.com/questions/2095974/… Commented Nov 6, 2015 at 11:53

3 Answers 3

2

Use two ad units. You can set up two banner ad units at AdMob.com, one with MillennialMedia in the mediation stack and one without. You can then check the API level of the device at runtime as Bonatti suggests, and set the ad unit ID on your AdView as appropriate prior to requesting ads.

If MillennialMedia is not in the mediation configuration for the ad unit being used, their adapter will not be instantiated by the Google Mobile Ads SDK.

Sign up to request clarification or add additional context in comments.

1 Comment

This workaround would do the job. BUT it is not satisfactory for me : I have a lot of ad networks in the mediation waterfall of my main ad unit ID, each with some country-specific CPM settings, which I update manually on a regular basis. Duplicating this ad unit would make the process of updating its mediation settings almost twice as long...
1

I am exactly in the same situation as you.

After doing a lot of research and black magic with class loaders, etc., I've found a dirty but working solution:

// At onCreate() or wherever it makes sense

if (Build.VERSION.SDK_INT < 16) {
    // Must be done before requesting the first ad
    disableMMediaAdapter();
}
m_adView.loadAd(adRequest);

// ...

private void disableMMediaAdapter()
{
    try {
        Field fInitialized = MMSDK.class.getField("initialized");
        fInitialized.setAccessible(true);
        fInitialized.set(null, true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

By tricking the SDK into believing it's initialized it will fail miserabily when an ad is requested through it and the next mediation adapter will be called.

This will work as long as they don't change their class desing too much.

1 Comment

Interesting approach! In the end my solution was to decompile their SDK and add a SDK check to throw an exception when API < 16.
0

Is there any way to prevent any future instantation of a given class at runtime? (e.g. by forcing a ClassNotFound exception)

You can, before loading the Adapter, check the OS version, and if its below your threshold

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.THE_VERSION_I_WANT_MINIMUM) {
   // doStuffs()
} else {
   throw new MyException("Stuffs have stuffened...");
}

1 Comment

Sorry if my question was unclear but this does not answer it. The important point is not checking the OS version, it is disabling a class from an external library.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.