Mopub:将 inmobi 原生广告与适配器 InMobiNative 集成

Mopub: integrating inmobi native ads with the adapter InMobiNative

似乎整个inmobi sdk从4.4.1到5.2.3发生了重大变化,这意味着我无法将inmobi sdk成功集成到mopub中。这是捆绑在 mopub sdk 中的适配器:

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

为方便起见,我已将代码复制并粘贴到此处 - 您可以看到作者已经说过该适配器是在 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();
        }
    }
}

有没有人成功地将此适配器转换为与最新的 5.2.3 inmobi sdk 一起使用?

4.4.1 的 sdk 甚至无法下载,如果没有 5.2.3 的适配器,恐怕无法与 inmobi 集成在 mopub 中?

我等了几天,没有收到 Inmobi 的任何回复,所以我决定自己调查一下如何解决这个问题。最终我可以浏览这个网站,它有一个带有 SDK 5.0.0 的示例应用程序,但是 class 似乎可以毫无问题地与 SDK 5.2.3 一起使用。

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

我必须阅读 class 并对适配器进行自己的调整才能正常工作 - 他们的适配器在使用已弃用的 class 时出现问题。所以这里是更新的适配器:

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);
                }
            });
        }


    }
}

那么你需要阅读这个网站,了解更多关于如何将他们的 SDK 集成到你的应用程序中的信息。您需要将其复制并粘贴到您的清单中:

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>

如果没有这些 classes,SDK 将不会初始化,您将在日志中收到错误消息。

请仔细阅读这两个网站,我只是在高层次上处理如何解决集成问题,但您还应该将其他内容添加到您的应用程序中,以使 mopub 与 inmobi 一起成功工作 Android.