【开发记录】小小一枚搬运工

写在前面

  没记错的话这边帖子在一个月前就开始起稿了,当时是想纪录一下穿山甲的接入过程。然而,项目开了加急,除了敲代码,其他活动基本处于瘫痪状态。现在终于有点时间来整理一下,把这段时间开发中遇到的问题,如何解决的都纪录一下。

主要内容

  • 穿山甲广告接入
  • 微信登录
  • 微信分享
  • 一、穿山甲的接入

      对android studio基本不熟,除了会打个包,其他基本看一眼就两眼发蒙。后面查了些资料,总算是接通了。

    参考资料:

      很幸运的找到前辈们写的接入文章,来回参考这些文章才让我把事情顺利做完。非常感谢前辈们的无私分享。
  • 笔记 : Android接入穿山甲SDK(ts和java互调注意事项)
  • CocosCreator接入穿山甲广告1-激励视频
  • CocosCreator接入穿山甲广告2-插屏广告
  • CocosCreator接入穿山甲广告3-底部banner

  • 官方网站(注册等录后在接入中心可以找到接入文档,如下图)
  • 图1.1 官方接入文档示例
  • 图1.2 官方接入文档SDK、参考示例、文档
    1、穿山甲视频广告接入
      a、导包:看xxx\jsb-link\frameworks\runtime-src\proj.android-studio\app下是否有libs文件夹,没有就新建一个,导入android-gif-drawable-1.2.6.aar.zip (258.9 KB) open_ad_sdk.zip (2.7 MB) 如此操作之后就可以了,不用再在build.gradle中添加什么依赖了。   b、在manifest中添加权限。   c、添加两个provider。provider的位置是在AndroidManifest.xml文件的如下位置
    <application>
         <activity .../>
         ...
        <provider
                android:name="com.bytedance.sdk.openadsdk.TTFileProvider"    //TTFileProvider报红?试试依赖中添加: implementation 'com.android.support:support-v4:27.1.1'
                android:authorities="包名.TTFileProvider" 
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths" />
            </provider>
           <provider
                android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
                android:authorities="包名.TTMultiProvider"
                android:exported="false" />
         ...
    </application>
    

      d、添加file_paths文件。右键项目名–>new–>xml–>App Actions xml file,填上名字‘file_paths‘,然后修改其中内容为:

    <?xml version="1.0" encoding="utf-8"?>
         <paths xmlns:android="http://schemas.android.com/apk/res/android">
         <!--为了适配所有路径可以设置 path = "." -->
         <external-path name="tt_external_root" path="." />
         <external-path name="tt_external_download" path="Download" />
         <external-files-path name="tt_external_files_download" path="Download" />
         <files-path name="tt_internal_file_download" path="Download" />
         <cache-path name="tt_internal_cache_download" path="Download" />
    </paths>
    

      e、开始撸代码。

    org.cocos2dx.javascript.AppActivity 同级目录新建TTAdManagerHolder、TTApplication类

        package org.cocos2dx.javascript;
        import android.content.Context;
        import com.bytedance.sdk.openadsdk.TTAdConfig;
        import com.bytedance.sdk.openadsdk.TTAdConstant;
        import com.bytedance.sdk.openadsdk.TTAdManager;
        import com.bytedance.sdk.openadsdk.TTAdSdk;
        public class TTAdManagerHolder {
            public static TTAdNative mTTAdNative;
            public static TTRewardVideoAd mttRewardVideoAd;
    
            private static boolean sInit;
            public static TTAdManager get() {
                if (!sInit) {
                    throw new RuntimeException("TTAdSdk is not init, please check.");
                }
                return TTAdSdk.getAdManager();
            }
            public static void init(Context context) {
                doInit(context);
            }
            //step1:接入网盟广告sdk的初始化操作,详情见接入文档和穿山甲平台说明
            private static void doInit(Context context) {
                if (!sInit) {
                    TTAdSdk.init(context, buildConfig(context));
                    sInit = true;
                }
            }
            private static TTAdConfig buildConfig(Context context) {
                return new TTAdConfig.Builder()
                        .appId("后台配置的应用id")  //
                        .useTextureView(true) //使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView
                        .appName("应用名字")
                        .titleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK)
                        .allowShowNotify(true) //是否允许sdk展示通知栏提示
                        .allowShowPageWhenScreenLock(true) //是否在锁屏场景支持展示广告落地页
                        .debug(true) //测试阶段打开,可以通过日志排查问题,上线时去除该调用
                        .directDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_3G) //允许直接下载的网络状态集合
                        .supportMultiProcess(false)//是否支持多进程
                        //.httpStack(new MyOkStack3())//自定义网络库,demo中给出了okhttp3版本的样例,其余请自行开发或者咨询工作人员。
                        .build();
            }
        }
    
       //激励视频广告
        public static void loadReawrdAd(final String codeId) {
            AdSlot adSlot = new AdSlot.Builder()
                    .setCodeId(codeId)
                    .setSupportDeepLink(true)
                    .setImageAcceptedSize(1080, 1920)
                    .setRewardAmount(1)  //奖励的数量
                    .setUserID("")//用户id,必传参数
                    .setOrientation(TTAdConstant.VERTICAL) //必填参数,期望视频的播放方向:TTAdConstant.HORIZONTAL 或 TTAdConstant.VERTICAL
                    .build();
            //step5:请求广告
            mTTAdNative.loadRewardVideoAd(adSlot, new TTAdNative.RewardVideoAdListener() {
                @Override
                public void onError(int code, String message) {
                    Log.e(TAG, message);//加载失败
                }
    
                //视频广告加载后,视频资源缓存到本地的回调,在此回调后,播放本地视频,流畅不阻塞。
                @Override
                public void onRewardVideoCached() {
                    Log.e(TAG, "rewardVideoAd video cached");
                }
    
                @Override
                public void onRewardVideoAdLoad(TTRewardVideoAd ad) {
                    Log.e(TAG, "rewardVideoAd loaded:"+ad);//加载成功
                    mttRewardVideoAd = ad;
                    mttRewardVideoAd.setRewardAdInteractionListener(new TTRewardVideoAd.RewardAdInteractionListener() {
    
                        @Override
                        public void onAdShow() {
                            Log.e(TAG, "rewardVideoAd show");
                        }
    
                        @Override
                        public void onAdVideoBarClick() {
                            Log.e(TAG, "rewardVideoAd bar click");
                        }
    
                        @Override
                        public void onAdClose() {
                            Log.e(TAG, "rewardVideoAd close");
                            //关闭后再次加载广告
                            //codeId = getRewardVideoId();
                            loadReawrdAd(codeId);
                        }
    
                        //视频播放完成回调
                        @Override
                        public void onVideoComplete() {
                            Log.e(TAG,"rewardVideoAd complete");
                            AppActivity._ins.jsLog("<=rewardVideoAd complete==>");
                        }
    
                        @Override
                        public void onVideoError() {
                            Log.e(TAG,"rewardVideoAd error");
                             //codeId = getRewardVideoId();
                            //loadReawrdAd(codeId ); 
                        }
    
                        //视频播放完成后,奖励验证回调,rewardVerify:是否有效,rewardAmount:奖励梳理,rewardName:奖励名称
                        @Override
                        public void onRewardVerify(boolean rewardVerify, int rewardAmount, String rewardName) {
                            Log.e(TAG,"rewardVideoAd rewardVerify:"+rewardVerify);
                           //AppActivity.sendTTRewardVerify(rewardVerify);  //发放奖励,在这里发放奖励,不知为什么有时会接收失败,我习惯在 onAdClose()里发放奖励。
                        }
    
                        @Override
                        public void onSkippedVideo() {
                        }
                    });
                }
            });
        }
    
        public static void setmTTAdNative(TTAdNative mTTAdNative){
            TTAdManagerHolder.mTTAdNative = mTTAdNative;
        }
    

        package org.cocos2dx.javascript;
        import android.app.Application;
        public class TTApplication extends Application {
                public void onCreate() {
                        super.onCreate();
                        TTAdManagerHolder.init(this);
                }
        }
    

    并在 AndroidManifest.xml中添加一行

     <application
            ...
            android:name="org.cocos2dx.javascript.TTApplication"
            ...
          >
    

      f、在AppActivity中的调用

    public class AppActivity extends Cocos2dxActivity {
        protected void onCreate(Bundle savedInstanceState) {
              ...
              TTAdManager ttAdManager = TTAdManagerHolder.get();
              TTAdManagerHolder.get().requestPermissionIfNecessary(this);
              TTAdManagerHolder.setmTTAdNative(ttAdManager.createAdNative(getApplicationContext()));
              TTAdManagerHolder.loadReawrdAd("123456789");
              ...
       }
       //展示穿山甲  视频  广告
       public static void showTTReward() {
            AppActivity._ins.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (TTAdManagerHolder.mttRewardVideoAd != null) {
                        TTAdManagerHolder.mttRewardVideoAd.showRewardVideoAd(AppActivity._ins);
                        TTAdManagerHolder.mttRewardVideoAd = null;
                    } else {
                        Log.e(AppActivity._ins.TAG, "请先加载广告");
                    }
                }
            });
        }
      }
    

                                                                                  五一快乐:grin:  2020.4.30

        从中遇到的问题:

  • 视频最好预加载,播完就拉取下一条,有可能遇到拉取出错的情况,要自己处理是否继续拉取,或者是切换新的广告id进行拉取
  • 广告的参数由js层传入,而js层从策划给的配置中去取
  • 关于奖励发放时机,这个没整明白,在onRewardVerify有时能拿到结果,有时却拿不到,无奈之下在onAdClose里进行的奖励发放。坐等高手指点①。
  • 2、穿山甲插屏广告接入

        参照其他前辈们的接入文章。     从中遇到的问题:
  • 需要预加载,需要达到立即显示的效果。可以将得到的实例保存下来,每个插屏广告在没有销毁之前都可以重复播放(showInteractionExpressAd),当播放一定次数之后或者间隔一段时间后再拉新的广告。
  • 3、穿山甲信息流广告接入

        在接这个之前都不知到这是个什么东西,官方给的解释是“在用户浏览阅读APP的推荐列表页、文章详情页、视频详情页中的原生图文及视频广告”,现在搞完了也不清楚,感觉就是接了一个卡片广告。坐等高手指点②。
        a、需要一个layout.xml文件。右键项目名-->new-->xml-->Layout xml file,填上名字‘activity_native_express.xml‘,然后修改其中内容为:
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <RelativeLayout
            android:id="@+id/express_container"
            android:layout_width="match_parent"
            android:layout_height="350dp"
            android:layout_alignParentBottom="true"/> 
    </RelativeLayout>
    

    (靠底,高350像素,按需调节,信息流广告将展示再express_container中)

        b、创建一个空view然后嵌入在cocos的界面上

        //我这里写在TTAdManagerHolder, 然后在AppActivity的oncreate中调用的
        public static void creatrView(){
            //原生的view直接添加到cocos的view内
            //R代表你是哪个包名的R文件,然后把创建好的view嵌入在你的cocosview里,不要使用setContentView(R.layout.activity_native_express);创建view
            View layout = LayoutInflater.from(AppActivity._ins).inflate(R.layout.activity_native_express, null);
            mFrameLayout = new FrameLayout(AppActivity._ins);
            mFrameLayout.addView(layout);
            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
            lp.bottomMargin = 0;
            AppActivity._ins.addContentView(mFrameLayout,lp);
            mExpressContainer = (RelativeLayout)AppActivity._ins.findViewById(R.id.express_container);
            //mFrameLayout.addView(view, layoutParams);
            //如已绘制SurfaceView则在surfaceView上一层绘制,必须addView之后使用
            //getGLSurfaceView().setZOrderMediaOverlay(true);
            //cocos的view是否在上层
            //getGLSurfaceView().setZOrderOnTop(true);
            AppActivity._ins.getGLSurfaceView().getHolder().setFormat(PixelFormat.TRANSLUCENT);
            mExpressContainer.setVisibility(View.GONE);
        }
    

    其中AppActivity._ins:

     public class AppActivity extends Cocos2dxActivity {
           ...
           public static AppActivity _ins;
           ...
           protected void onCreate(Bundle savedInstanceState) {
              ...
              AppActivity._ins = this;
              ...
          }
     }
    

        c、撸代码

        public static TTNativeExpressAd mttNEAd;
        public static View NEView = new View();
        public static FrameLayout mFrameLayout;   //在creatrView中创建的
        public static RelativeLayout mExpressContainer;//在creatrView中创建的
        //信息流广告 TTNativeAd
        public static void loadTTNativeAd(final  String codeId){
            AdSlot adSlot = new AdSlot.Builder()
                    .setCodeId(codeId) //广告位id
                    .setSupportDeepLink(true)
                    .setAdCount(1) //请求广告数量为1到3条
                    .setExpressViewAcceptedSize(350,600) //期望个性化模板广告view的size,单位dp
                    .setImageAcceptedSize(350,600) //这个参数设置即可,不影响个性化模板广告的size
                    .build();
            mTTAdNative.loadNativeExpressAd(adSlot, new TTAdNative.NativeExpressAdListener() {
                @Override
                public void onError(int code, String message) {
                    Log.e(TAG,"loadTTNativeAd error:"+message);
                }
    
                @Override
                public void onNativeExpressAdLoad(List<TTNativeExpressAd> ads) {
                    if (ads == null || ads.size() == 0){
                        Log.e(TAG,"loadFeedAd ad is null");
                        return;
                    }
                    mttNEAd = ads.get(0);
                    bindAdListener(mttNEAd);
                    bindDislike(mttNEAd, false);
                    mttNEAd.render();//调用render开始渲染广告
                }
    
                private void bindAdListener(TTNativeExpressAd ad) {
                    ad.setExpressInteractionListener(new TTNativeExpressAd.ExpressAdInteractionListener() {
                        @Override
                        public void onAdClicked(View view, int type) {
                            Log.e(TAG,"信息流广告被点击");
                        }
    
                        @Override
                        public void onAdShow(View view, int type) {
                            Log.e(TAG,"信息流广告展示在mExpressContainer中");
                        }
    
                        @Override
                        public void onRenderFail(View view, String msg, int code) {
                            Log.e(TAG,"信息流 render fail");
                           // loadTTNativeAd(nextCodeId);
                        }
    
                        @Override
                        public void onRenderSuccess(final View view, float width, float height) {
                            Log.e(TAG,"信息流广告"+idx+"渲染成功");
                            NEView = view;
                        }
                    });
                }
                /**
                 * 设置广告的不喜欢,注意:强烈建议设置该逻辑,如果不设置dislike处理逻辑,则模板广告中的 dislike区域不响应dislike事件。
                 * @param ad
                 * @param customStyle 是否自定义样式,true:样式自定义
                 */
                private void bindDislike(TTNativeExpressAd ad, boolean customStyle) {
                    //使用默认模板中默认dislike弹出样式
                    ad.setDislikeCallback(AppActivity._ins, new TTAdDislike.DislikeInteractionCallback() {
                        @Override
                        public void onSelected(int position, String value) {
                            //用户选择不喜欢原因后,移除广告展示
                            Log.e(TAG,"dislike 移除广告展示");
                            mExpressContainer.removeAllViews();
                        }
    
                        @Override
                        public void onCancel() {
                            Log.e(TAG,"dislike 移除广告展示");
                        }
                    });
                }
            });
        }
    
        //显示信息流广告
        public static void showTTNativeAd(){
            AppActivity._ins.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mExpressContainer.removeAllViews();
                    mExpressContainer.addView(NEView);
                    mExpressContainer.setVisibility(View.VISIBLE);
                }
            });
        }
        //关闭信息流广告
        public static void closeTTNativeAd(){
            AppActivity._ins.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                   mExpressContainer.setVisibility(View.GONE);
                   /*销毁
                   mExpressContainer.removeAllViews();
                   if(mttNEAd != null){
                        mttNEAd.destroy();
                        mttNEAd = null;
                    }
                    NEView = null;
                   */
                }
            });
        }
    

        从中遇到的问题:

  • 宽高。一开始在adSlot中填了个720 * 1780的尺寸,拉下来的广告歪七扭八的,后面调了下才搞对
  • 对齐。在activity_native_express.xml中调整android:layout_width、 android:layout_height、android:layout_alignParentBottom等
  • 显示、隐藏、替换。渲染在自定义的view中,可以通过setVisibility来控制显示隐藏,通过removeAllViews、addView来替换广告

  •                                                          哎,天天加班,头发掉一地。周末快乐:grin:  2020.5.10

    二、微信登录

    三、微信分享

    技能cd中...

    12赞

    穿山甲需要版号吗

    关注。。。。

    不清楚,好像不需要,只负责接这些东西,像资质这些其他的都是运营在搞。

    请教下这个报错
    Unable to get provider com.bytedance.sdk.openadsdk.TTFileProvider: java.lang.ClassNotFoundException: Didn’t find class “com.bytedance.sdk.openadsdk.TTFileProvider”
    是什么原因呢
    TTFileProvider配置如下

    是不是这里报错了,我写的是:
    android:authorities="${applicationId}.TTFileProvider"
    而你这里是
    android:authorities=“包名.TTFileProvider”

    战略性Mark!

    mark00000

    解决了吗,我遇到同样的问题

    在主模块的build.gradle添加,implementation “com.android.support:support-v4:28.0.0”,support-v4具体哪个版本看头条demo里用的什么

    1赞