javaandroidmopubinmobi

Mopub: integrating inmobi native ads with the adapter InMobiNative


It appears that the whole inmobi sdk has changed significantly from 4.4.1 to 5.2.3 which means that I cannot integrate the inmobi sdk successfully into mopub. This is adapter bundled within the mopub sdk:

https://github.com/motain/android-ads-MoPub/blob/master/extras/src/com/mopub/nativeads/InMobiNative.java

I have copied and pasted the code here for your convenience - you can see that the author has said that the adapter was tested on 4.4.1:

package com.mopub.nativeads;

import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

import com.inmobi.commons.InMobi;
import com.inmobi.monetization.IMErrorCode;
import com.inmobi.monetization.IMNative;
import com.inmobi.monetization.IMNativeListener;
import com.mopub.common.util.MoPubLog;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.mopub.common.util.Json.getJsonValue;
import static com.mopub.common.util.Numbers.parseDouble;

/*
 * Tested with InMobi SDK 4.4.1
 */
class InMobiNative extends CustomEventNative implements IMNativeListener {
    private static final String APP_ID_KEY = "app_id";

    private Context mContext;
    private CustomEventNativeListener mCustomEventNativeListener;

    // CustomEventNative implementation
    @Override
    protected void loadNativeAd(final Context context,
            final CustomEventNativeListener customEventNativeListener,
            final Map<String, Object> localExtras,
            final Map<String, String> serverExtras) {

        mContext = context;

        if (!(context instanceof Activity)) {
            customEventNativeListener.onNativeAdFailed(NativeErrorCode.NATIVE_ADAPTER_CONFIGURATION_ERROR);
            return;
        }
        final Activity activity = (Activity) context;

        final String appId;
        if (extrasAreValid(serverExtras)) {
            appId = serverExtras.get(APP_ID_KEY);
        } else {
            customEventNativeListener.onNativeAdFailed(NativeErrorCode.NATIVE_ADAPTER_CONFIGURATION_ERROR);
            return;
        }

        mCustomEventNativeListener = customEventNativeListener;

        InMobi.initialize(activity, appId);
        final IMNative imNative = new IMNative(this);
        imNative.loadAd();
    }

    // IMNativeListener implementation
    @Override
    public void onNativeRequestSucceeded(final IMNative imNative) {
        if (imNative == null) {
            mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_STATE);
            return;
        }

        final InMobiForwardingNativeAd inMobiForwardingNativeAd;
        try {
            inMobiForwardingNativeAd = new InMobiForwardingNativeAd(imNative);
        } catch (IllegalArgumentException e) {
            mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.UNSPECIFIED);
            return;
        } catch (JSONException e) {
            mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.INVALID_JSON);
            return;
        }

        final List<String> imageUrls = new ArrayList<String>();
        final String mainImageUrl = inMobiForwardingNativeAd.getMainImageUrl();
        if (mainImageUrl != null) {
            imageUrls.add(mainImageUrl);
        }
        final String iconUrl = inMobiForwardingNativeAd.getIconImageUrl();
        if (iconUrl != null) {
            imageUrls.add(iconUrl);
        }

        preCacheImages(mContext, imageUrls, new ImageListener() {
            @Override
            public void onImagesCached() {
                mCustomEventNativeListener.onNativeAdLoaded(inMobiForwardingNativeAd);
            }

            @Override
            public void onImagesFailedToCache(NativeErrorCode errorCode) {
                mCustomEventNativeListener.onNativeAdFailed(errorCode);
            }
        });
    }

    @Override
    public void onNativeRequestFailed(final IMErrorCode errorCode) {
        if (errorCode == IMErrorCode.INVALID_REQUEST) {
            mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_REQUEST);
        } else if (errorCode == IMErrorCode.INTERNAL_ERROR || errorCode == IMErrorCode.NETWORK_ERROR) {
            mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_STATE);
        } else if (errorCode == IMErrorCode.NO_FILL) {
            mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_NO_FILL);
        } else {
            mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.UNSPECIFIED);
        }
    }

    private boolean extrasAreValid(final Map<String, String> serverExtras) {
        final String placementId = serverExtras.get(APP_ID_KEY);
        return (placementId != null && placementId.length() > 0);
    }

    static class InMobiForwardingNativeAd extends BaseForwardingNativeAd {
        static final int IMPRESSION_MIN_TIME_VIEWED = 0;

        // Modifiable keys
        static final String TITLE = "title";
        static final String DESCRIPTION = "description";
        static final String SCREENSHOTS = "screenshots";
        static final String ICON = "icon";
        static final String LANDING_URL = "landing_url";
        static final String CTA = "cta";
        static final String RATING = "rating";

        // Constant keys
        static final String URL = "url";

        private final IMNative mImNative;

        InMobiForwardingNativeAd(final IMNative imNative) throws IllegalArgumentException, JSONException {
            if (imNative == null) {
                throw new IllegalArgumentException("InMobi Native Ad cannot be null");
            }

            mImNative = imNative;

            final JSONTokener jsonTokener = new JSONTokener(mImNative.getContent());
            final JSONObject jsonObject = new JSONObject(jsonTokener);

            setTitle(getJsonValue(jsonObject, TITLE, String.class));
            setText(getJsonValue(jsonObject, DESCRIPTION, String.class));

            final JSONObject screenShotJsonObject = getJsonValue(jsonObject, SCREENSHOTS, JSONObject.class);
            if (screenShotJsonObject != null) {
                setMainImageUrl(getJsonValue(screenShotJsonObject, URL, String.class));
            }

            final JSONObject iconJsonObject = getJsonValue(jsonObject, ICON, JSONObject.class);
            if (iconJsonObject != null) {
                setIconImageUrl(getJsonValue(iconJsonObject, URL, String.class));
            }

            setClickDestinationUrl(getJsonValue(jsonObject, LANDING_URL, String.class));
            setCallToAction(getJsonValue(jsonObject, CTA, String.class));

            try {
                setStarRating(parseDouble(jsonObject.opt(RATING)));
            } catch (ClassCastException e) {
                MoPubLog.d("Unable to set invalid star rating for InMobi Native.");
            }
            setImpressionMinTimeViewed(IMPRESSION_MIN_TIME_VIEWED);
        }

        @Override
        public void prepareImpression(final View view) {
            if (view != null && view instanceof ViewGroup) {
                mImNative.attachToView((ViewGroup) view);
            } else if (view != null && view.getParent() instanceof ViewGroup) {
                mImNative.attachToView((ViewGroup) view.getParent());
            } else {
                MoPubLog.e("InMobi did not receive ViewGroup to attachToView, unable to record impressions");
            }
        }

        @Override
        public void handleClick(final View view) {
            mImNative.handleClick(null);
        }

        @Override
        public void destroy() {
            mImNative.detachFromView();
        }
    }
}

Has anyone been successful in converting this adapter to work with the latest 5.2.3 inmobi sdk?

The 4.4.1 sdk is not even available to download anymore and if there is no adapter for 5.2.3, then I'm afraid inmobi integration with in mopub is not possible?


Solution

  • I waited a few days and did not get any response back from Inmobi so I decided to do some investigation myself on how to solve this issue. Eventually I can across this website which had a sample app with SDK 5.0.0 but the class seems to work with SDK 5.2.3 without any problems.

    https://support.inmobi.com/monetize/integration/mediation-adapters/mopub-adaptor-android-sdk-integration-guide/#getting-started

    I had to read the class and make my own adjustments to the adapter so that it will work - their adapter had issues as they were using deprecated classes. So here is the updated adapter:

    package com.mopub.nativeads;
    
    import android.app.Activity;
    import android.content.Context;
    import android.support.annotation.NonNull;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    
    import com.inmobi.ads.InMobiAdRequestStatus;
    import com.inmobi.sdk.InMobiSdk;
    import com.mopub.common.MoPub;
    import com.mopub.common.logging.MoPubLog;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    import org.json.JSONTokener;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import static com.mopub.common.util.Json.getJsonValue;
    import static com.mopub.common.util.Numbers.parseDouble;
    import static com.mopub.nativeads.NativeImageHelper.preCacheImages;
    
    /*
     * Tested with InMobi SDK 5.2.3
     */
    public class InMobiNative extends CustomEventNative {
    
    
        private static boolean isAppIntialize = false;
        private JSONObject serverParams;
        private String accountId="XXX";
        private long placementId=123L;
    
    
        @Override
        protected void loadNativeAd(@NonNull Activity arg0,
                                    @NonNull CustomEventNativeListener arg1,
                                    @NonNull Map<String, Object> arg2,
                                    @NonNull Map<String, String> arg3) {
    
            // TODO Auto-generated method stub
            Log.d("InMobiNativeCustomEvent", "Reached native adapter");
            try {
                serverParams = new JSONObject(arg3);
            } catch (Exception e) {
                Log.e("InMobi", "Could not parse server parameters");
                e.printStackTrace();
            }
    
            Activity activity = null;
            if (arg0 instanceof Activity) {
                activity = arg0;
            } else {
                // You may also pass in an Activity Context in the localExtras map
                // and retrieve it here.
            }
            if (activity == null) {
                arg1.onNativeAdFailed(NativeErrorCode.NATIVE_ADAPTER_CONFIGURATION_ERROR);
                return;
            }
            try {
                accountId = serverParams.getString("accountid");
                placementId = serverParams.getLong("placementId");
            } catch (JSONException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
    
            if (!isAppIntialize) {
                try {
    
                    InMobiSdk.init(activity,"accountid");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                isAppIntialize = true;
            }
            InMobiSdk.setAreaCode("areacode");
            InMobiSdk.setEducation(InMobiSdk.Education.HIGH_SCHOOL_OR_LESS);
            InMobiSdk.setGender(InMobiSdk.Gender.MALE);
            InMobiSdk.setIncome(1000);
            InMobiSdk.setAge(23);
            InMobiSdk.setPostalCode("postalcode");
            InMobiSdk.setLogLevel(InMobiSdk.LogLevel.DEBUG);
            InMobiSdk.setLocationWithCityStateCountry("blore", "kar", "india");
            InMobiSdk.setLanguage("ENG");
            InMobiSdk.setInterests("dance");
            InMobiSdk.setEthnicity(InMobiSdk.Ethnicity.ASIAN);
            InMobiSdk.setYearOfBirth(1980);
            Map<String, String> map = new HashMap<String, String>();
            map.put("tp", "c_mopub");
            map.put("tp-ver", MoPub.SDK_VERSION);
            final InMobiStaticNativeAd inMobiStaticNativeAd =
                    new InMobiStaticNativeAd(arg0,
                            new ImpressionTracker(arg0),
                            new NativeClickHandler(arg0),
                            arg1);
            inMobiStaticNativeAd.setIMNative(new com.inmobi.ads.InMobiNative(placementId, inMobiStaticNativeAd));
            inMobiStaticNativeAd.setExtras(map);
            inMobiStaticNativeAd.loadAd();
        }
    
    
        static class InMobiStaticNativeAd extends StaticNativeAd implements com.inmobi.ads.InMobiNative.NativeAdListener {
            static final int IMPRESSION_MIN_TIME_VIEWED = 1000;
    
            // Modifiable keys
            static final String TITLE = "title";
            static final String DESCRIPTION = "description";
            static final String SCREENSHOTS = "screenshots";
            static final String ICON = "icon";
            static final String LANDING_URL = "landingURL";
            static final String CTA = "cta";
            static final String RATING = "rating";
    
            // Constant keys
            static final String URL = "url";
    
            private final Context mContext;
            private final CustomEventNativeListener mCustomEventNativeListener;
            private final ImpressionTracker mImpressionTracker;
            private final NativeClickHandler mNativeClickHandler;
            private com.inmobi.ads.InMobiNative mImNative;
    
            InMobiStaticNativeAd(final Context context,
                                 final ImpressionTracker impressionTracker,
                                 final NativeClickHandler nativeClickHandler,
                                 final CustomEventNativeListener customEventNativeListener) {
                InMobiSdk.init(context,"9107a61fcda34c969d3f74934a352dcb");
                mContext = context.getApplicationContext();
                mImpressionTracker = impressionTracker;
                mNativeClickHandler = nativeClickHandler;
                mCustomEventNativeListener = customEventNativeListener;
            }
    
            void setIMNative(final com.inmobi.ads.InMobiNative imNative) {
                mImNative = imNative;
            }
    
            void setExtras(Map<String,String> map){
                mImNative.setExtras(map);
            }
    
            void loadAd() {
                mImNative.load();
            }
    
    
            // Lifecycle Handlers
            @Override
            public void prepare(final View view) {
                if (view != null && view instanceof ViewGroup) {
                    com.inmobi.ads.InMobiNative.bind((ViewGroup)view, mImNative);
                } else if (view != null && view.getParent() instanceof ViewGroup) {
                    com.inmobi.ads.InMobiNative.bind((ViewGroup)(view.getParent()), mImNative);
                } else {
                    Log.e("MoPub", "InMobi did not receive ViewGroup to attachToView, unable to record impressions");
                }
                mImpressionTracker.addView(view, this);
                mNativeClickHandler.setOnClickListener(view, this);
            }
    
            @Override
            public void clear(final View view) {
                mImpressionTracker.removeView(view);
                mNativeClickHandler.clearOnClickListener(view);
            }
    
            @Override
            public void destroy() {
                //InMobiNative.unbind(arg0);
                mImpressionTracker.destroy();
            }
    
            // Event Handlers
            @Override
            public void recordImpression(final View view) {
                notifyAdImpressed();
            }
    
            @Override
            public void handleClick(final View view) {
                notifyAdClicked();
                mNativeClickHandler.openClickDestinationUrl(getClickDestinationUrl(), view);
                mImNative.reportAdClick(null);
            }
    
            void parseJson(final com.inmobi.ads.InMobiNative inMobiNative) throws JSONException  {
                final JSONTokener jsonTokener = new JSONTokener((String) inMobiNative.getAdContent());
                final JSONObject jsonObject = new JSONObject(jsonTokener);
    
                setTitle(getJsonValue(jsonObject, TITLE, String.class));
                String text = getJsonValue(jsonObject, DESCRIPTION, String.class);
                if(text!=null)
                    setText(text);
                final JSONObject screenShotJsonObject = getJsonValue(jsonObject, SCREENSHOTS, JSONObject.class);
                if (screenShotJsonObject != null) {
                    setMainImageUrl(getJsonValue(screenShotJsonObject, URL, String.class));
                }
    
                final JSONObject iconJsonObject = getJsonValue(jsonObject, ICON, JSONObject.class);
                if (iconJsonObject != null) {
                    setIconImageUrl(getJsonValue(iconJsonObject, URL, String.class));
                }
    
                final String clickDestinationUrl = getJsonValue(jsonObject, LANDING_URL, String.class);
                if (clickDestinationUrl == null) {
                    final String errorMessage = "InMobi JSON response missing required key: "
                            + LANDING_URL + ". Failing over.";
                    MoPubLog.d(errorMessage);
                    throw new JSONException(errorMessage);
                }
    
                setClickDestinationUrl(clickDestinationUrl);
                String cta = getJsonValue(jsonObject, CTA, String.class);
                if(cta!=null)
                    setCallToAction(cta);
                try {
                    if(jsonObject.opt(RATING)!=null){
                        setStarRating(parseDouble(jsonObject.opt(RATING)));
                    }
                } catch (ClassCastException e) {
                    Log.d("MoPub", "Unable to set invalid star rating for InMobi Native.");
                }            setImpressionMinTimeViewed(IMPRESSION_MIN_TIME_VIEWED);
            }
    
            @Override
            public void onAdDismissed(com.inmobi.ads.InMobiNative inMobiNative) {
                // TODO Auto-generated method stub
                Log.d("InMobiNativeCustomEvent","Native Ad is dismissed");
            }
    
            @Override
            public void onAdDisplayed(com.inmobi.ads.InMobiNative inMobiNative) {
                // TODO Auto-generated method stub
                Log.d("InMobiNativeCustomEvent","Native Ad is displayed");
            }
    
            @Override
            public void onAdLoadFailed(com.inmobi.ads.InMobiNative arg0, InMobiAdRequestStatus arg1) {
                // TODO Auto-generated method stub
                Log.d("InMobiNativeCustomEvent","Native ad failed to load");
                String errorMsg="";
                switch (arg1.getStatusCode()) {
                    case INTERNAL_ERROR:
                        errorMsg="INTERNAL_ERROR";
                        break;
                    case REQUEST_INVALID:
                        errorMsg="INVALID_REQUEST";
                        break;
                    case NETWORK_UNREACHABLE:
                        errorMsg="NETWORK_UNREACHABLE";
                        break;
                    case NO_FILL:
                        errorMsg="NO_FILL";
                        break;
                    case REQUEST_PENDING:
                        errorMsg="REQUEST_PENDING";
                        break;
                    case REQUEST_TIMED_OUT:
                        errorMsg="REQUEST_TIMED_OUT";
                        break;
                    case SERVER_ERROR:
                        errorMsg="SERVER_ERROR";
                        break;
                    case AD_ACTIVE:
                        errorMsg="AD_ACTIVE";
                        break;
                    case EARLY_REFRESH_REQUEST:
                        errorMsg="EARLY_REFRESH_REQUEST";
                        break;
                    default:
                        errorMsg="NETWORK_ERROR";
                        break;
                }
                if (errorMsg == "INVALID_REQUEST") {
                    mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_REQUEST);
                } else if (errorMsg == "INTERNAL_ERROR" || errorMsg == "NETWORK_ERROR") {
                    mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_INVALID_STATE);
                } else if (errorMsg == "NO_FILL") {
                    mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_NO_FILL);
                } else if (errorMsg == "REQUEST_TIMED_OUT"){
                    mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.NETWORK_TIMEOUT);
                }else if(errorMsg == "NETWORK_UNREACHABLE"){
                    mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.CONNECTION_ERROR);
                }
                else {
                    mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.UNSPECIFIED);
                }
            }
    
    
            @Override
            public void onUserLeftApplication(com.inmobi.ads.InMobiNative arg0) {
                // TODO Auto-generated method stub
                Log.d("InMobiNativeCustomEvent","User left application");
            }
    
            @Override
            public void onAdLoadSucceeded(com.inmobi.ads.InMobiNative inMobiNative) {
                // TODO Auto-generated method stub
                Log.v("InMobiNativeCustomEvent", "Ad loaded:"+inMobiNative.getAdContent().toString());
                try {
                    parseJson(inMobiNative);
                } catch (JSONException e) {
                    mCustomEventNativeListener.onNativeAdFailed(NativeErrorCode.INVALID_RESPONSE);
                    return;
                }
    
                final List<String> imageUrls = new ArrayList<String>();
                /*final String mainImageUrl = getMainImageUrl();
                if (mainImageUrl != null) {
                    imageUrls.add(mainImageUrl);
                }*/
    
                final String iconUrl = getIconImageUrl();
                if (iconUrl != null) {
                    imageUrls.add(iconUrl);
                }
    
                preCacheImages(mContext, imageUrls, new NativeImageHelper.ImageListener() {
                    @Override
                    public void onImagesCached() {
                        Log.v("InMobiNativeCustomEvent", "image cached");
                        mCustomEventNativeListener.onNativeAdLoaded(InMobiStaticNativeAd.this);
                    }
    
                    @Override
                    public void onImagesFailedToCache(NativeErrorCode errorCode) {
                        Log.v("InMobiNativeCustomEvent", "image failed to cache");
                        mCustomEventNativeListener.onNativeAdFailed(errorCode);
                    }
                });
            }
    
    
        }
    }
    

    Then you need to read this website telling you more about how to integrate their SDK into your app. You need to copy and paste this into your manifest:

    https://support.inmobi.com/android-sdk-integration-guide/#getting-started

    <activity android:name="com.inmobi.rendering.InMobiAdActivity"
    android:configChanges="keyboardHidden|orientation|keyboard|smallestScreenSize|screenSize"
    android:theme="@android:style/Theme.Translucent.NoTitleBar"
    android:hardwareAccelerated="true" />
    
    <receiver
    android:name="com.inmobi.commons.core.utilities.uid.ImIdShareBroadCastReceiver"
    android:enabled="true"
    android:exported="true" >
    <intent-filter>
    <action android:name="com.inmobi.share.id" />
    </intent-filter>
    </receiver>
    

    Without these classes, the SDK will not initialize and you will get an error in the logs.

    Please do read through both websites, I'm just dealing on a high level on how you can solve the integration but there are other stuff you should put into your app to make mopub work successfully with inmobi for Android.