カスタムインフィード広告

簡易版インフィード広告よりも柔軟な表示を行いたい場合などに、カスタム型のインフィード広告機能を利用することが出来ます。

カスタムインフィード広告では自動で広告イベントを送信しないため、アプリケーション側で実装する必要があります。

広告レイアウトの作成

通常のレイアウト同様に作成します。

レイアウト作成時に広告箇所が広告であることをユーザーが視認・理解できる文言を必ず配置して下さい。 displayedAdvertiserを使うことで広告ごとに適切な文言を表示することが出来ます。

広告の表示に用いるパラメータ

パラメータ名 説明
title タイトル文言(全角20文字以内) TestAd
content 説明・紹介文(全角40〜70文字以内) テスト広告です。
position 広告案件の相対位置 3
displayedAdvertiser 表記広告主名 飲料会社 A社
creative_url バナー画像URL https://example.com/image.jpg
creative_width バナー画像(またはVideo)のサイズ(幅) 640
creative_height バナー画像(またはVideo)のサイズ(高さ) 360

広告リクエストの送信

RFPInstreamAdLoader.Builderを使用してRFPInstreamAdLoaderのインスタンスを生成し、loadAd(Context)を使用して広告リクエストを送信します。

    RFPInstreamAdLoader adLoader = new RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID").build();
    adLoader.loadAd(context); // 広告読み込み開始
    

    val adLoader = RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID").build()
    adLoader.loadAd(context) // 広告読み込み開始
    

    取得する広告の数は引数により指定できます。

      Integer[] p = {0, 3, 6};
      List<Integer> positions = Arrays.asList(p);
      int count = positions.size();
      RFPInstreamAdLoader adLoader = new RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID")
          .count(count)
          .positions(positions)
          .build();
      adLoader.loadAd(context); // 広告読み込み開始
      

      val positions = mutableListOf(0, 3, 6)
      val count = positions.size
      val adLoader = RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID")
          .count(count)
          .positions(positions)
          .build()
      adLoader.loadAd(context) // 広告読み込み開始
      

      positionsインフィード内における広告の位置を示すものとなります。
      上記の例の場合、1番目、4番目、7番目の位置に広告を挿入するイメージとなります。

      カスタムパラメータの送信

      SDK v3.8.4からカスタムパラメータの送信に対応しました。

      (カスタムパラメータの詳細は担当者にお問い合わせください)

      RFPInstreamAdLoader.Builder#data() でパラメータを指定することができます。

      val loader = RFPInstreamAdLoader.Builder(spotId)
              .count(count)
              .positions(positions)
              // 個別に設定
              .data("key1", "xyzzy")
              .data("key2", arrayOf("foo", "bar", "baz"))
              // または Bundle で一括
              // .data(bundleOf("key1" to "xyzzy", "key2" to arrayOf("foo", "bar", "baz")))
              .build()
      loader.loadAd(context)
      

      広告の取得

      取得した広告はリスナーに通知されるので、あらかじめ RFPInstreamAdLoader#onSuccess を実装し設定しておく必要があります。

        RFPInstreamAdLoader adLoader = new RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID")
            .onSuccess(new RFPInstreamAdLoader.OnSuccess() {
                           @Override
                           public void onSuccess(List<RFPInstreamInfoModel> items) {
                                // 広告のロード完了時
                           }
                       })
            .build();
        adLoader.loadAd(context); // 広告読み込み開始
        

        val adLoader = RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID")
            .onSuccess { items ->
                // 広告のロード完了時
            }
            .build()
        adLoader.loadAd(context) // 広告読み込み開始
        

        広告の表示

        広告パラメータはRFPInstreamAdLoader.OnSuccess.onSuccess()によって、RFPInstreamInfoModelの配列として取得できます。 これをもとにビューを構築します。

          RFPInstreamAdLoader adLoader = new RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID")
              .onSuccess(new RFPInstreamAdLoader.OnSuccess() {
                             @Override
                             public void onSuccess(List<RFPInstreamInfoModel> items) {
                                  yourContentsItemList.add(0, items.get(0));
                                  yourContentsItemList.add(3, items.get(1));
                                  yourContentsItemList.add(6, items.get(2));
                             }
                         })
              .build();
          
          class YourAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
              List<Object> yourContentsItemList;
          
              /**
               * @param yourContentsItemList コンテンツの元となるアイテムのリスト
               */
              YourAdapter(List<Object> yourContentsItemList) {
                  this.yourContentsItemList = yourContentsItemList;
              }
          
              @Override
              public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                  LayoutInflater inflater = LayoutInflater.from(parent.getContext());
                  if (viewType == VIEW_TYPE_AD) { // 広告
                      View v = inflater.inflate(R.layout.ad_view, parent, false);
                      return new AdViewHolder(v);
                  }
          
                  View v = inflater.inflate(R.layout.content_view, parent, false);
                  return new ContentViewHolder(v);
              }
          
              @Override
              public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
                  Object content = yourContentsItemList.get(position);
          
                  if (content instanceof RFPInstreamInfoModel) { // 広告
                      RFPInstreamInfoModel adModel = (RFPInstreamInfoModel) content;
                      AdViewHolder adHolder = (AdViewHolder) holder;
                      adHolder.bindData(adModel);
                      return;
                  }
          
                  YourContent yourContent = (YourContent) content;
                  ContentViewHolder viewHolder = (ContentViewHolder) holder;
                  viewHolder.bindData(yourContent);
              }
          
              /**
               * コンテンツ用ViewHolder
               */
              private static class ContentViewHolder extends RecyclerView.ViewHolder {
                  // ... ...
              }
          
              /**
               * 広告用ViewHolder
               */
              private static class AdViewHolder extends RecyclerView.ViewHolder {
                  // ... ...
              }
          }
          

          val adLoader = RFPInstreamAdLoader.Builder("YOUR_ADSPOT_ID")
              .onSuccess { items ->
                  items?.let {
                      yourContentsItemList.add(0, it[0])
                      yourContentsItemList.add(3, it[1])
                      yourContentsItemList.add(6, it[2])
                  }
              }
              .build()
          
          class YourAdapter(private yourContentsItemList: List<Any>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
              override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
                  val inflater = LayoutInflater.from(parent.context)
                  if (viewType == VIEW_TYPE_AD) {
                      val v = inflater.inflate(R.layout.ad_view, parent, false)
                      return AdViewHolder(v)
                  }
          
                  val v = inflater.inflate(R.layout.content_view, parent, false)
                  return ContentViewHolder(v)
              }
          
              override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
                  if (holder.itemViewType == VIEW_TYPE_AD) {
                      val model = yourContentsItemList[position] as RFPInstreamInfoModel
                      val vh = holder as AdViewHolder
                      vh.bindData(model)
                      return;
                  }
          
                  val yourContent = yourContentsItemList[position] as YourContent
                  val vh = holder as ContentViewHolder
                  vh.bindData(yourContent)
              }
          
              private class ContentViewHolder(itemView: View)
                  : RecyclerView.ViewHolder(itemView) {
                  // ... ...
              }
          
              private class AdViewHolder(itemView: View)
                  : RecyclerView.ViewHolder(itemView) {
                  // ... ...
              }
          }
          

          RFPInstreamInfoModelの内容を元にビューを構築します。

            private static class AdViewHolder extends RecyclerView.ViewHolder {
                TextView advertiserName;
                TextView adText;
                ImageView adImage;
                TextView adSponsoredLabel;
            
                AdViewHolder(View itemView) {
                    super(itemView);
            
                    advertiserName = itemView.findViewById(R.id.advertiser_name);
                    adText = itemView.findViewById(R.id.ad_text);
                    adImage = itemView.findViewById(R.id.ad_image);
                    adSponsoredLabel = itemView.findViewById(R.id.sponsor_name);
                }
            
                void bindData(RFPInstreamInfoModel model) {
                    Log.d(TAG, "Ad ID is " + model.ad_id());
            
                    advertiserName.setText(model.title());
                    adText.setText(model.content());
                    adSponsoredLabel.setText(model.displayedAdvertiser());
            
                    loadImageFromUrl(adImage, model.creative_url());
                }
            
                private void loadImageFromUrl(ImageView view, String url) {
                    // ... ...
                }
            }
            

            private class AdViewHolder(itemView: View)
                : RecyclerView.ViewHolder(itemView) {
                val advertiserName: TextView = itemView.findViewById(R.id.advertiser_name)
                val adText: TextView = itemView.findViewById(R.id.ad_text)
                val adImage: ImageView = itemView.findViewById(R.id.ad_image)
                val adSponsoredLabel: TextView = itemView.findViewById(R.id.sponsor_name)
            
                fun bindData(model: RFPInstreamInfoModel) {
                    advertiserName.text = model.title()
                    adText.text = model.content()
                    adSponsoredLabel.text = model.displayedAdvertiser()
                    loadImageFromUrl(adImage, model.creative_url())
                }
            
                fun loadImageFromUrl(view: ImageView, url: String) {
                    // ... ...
                }
            }
            

            アニメーションGIF広告への対応

            SDKがアニメーションGIFの再生を直接サポートしていないため、 アニメーションGIF広告を再生するには MovieまたはAnimatedImageDrawableを用いて独自に実装するか、Glideなどサードパーティ製のライブラリを利用して実装する必要があります。

            広告のイベントの送信

            カスタムインフィード広告ではイベントを自動で送信しないため、クリックおよびインプレッションの送信を実装する必要があります。

            クリックイベントの送信

            広告枠をクリックが発生した場合、RFPInstreamAdEvent#sendClickEvent()を呼ぶ必要があります。

            このメソッドはイベントの送信と同時にLPへの遷移も行うため、これだけで完結します。

              private static class AdViewHolder extends RecyclerView.ViewHolder
                      implements View.OnClickListener {
                  RFPInstreamInfoModel adModel;
              
                  // ... ...
              
                  AdViewHolder(View itemView) {
                      // ... ...
              
                      itemView.setOnClickListener(this);
              
                      // ... ...
                  }
              
                  void bindData(RFPInstreamInfoModel model) {
                      adModel = model;
                      // ... ...
                  }
              
                  // ... ...
              
                  @Override
                  public void onClick(View view) {
                      // クリックイベントの送信とLPへの遷移
                      RFPInstreamAdEvent.sendClickEvent(view.getContext(), adModel);
                  }
              }
              

              private class AdViewHolder(itemView: View)
                  : RecyclerView.ViewHolder(itemView), View.OnClickListener {
                  var adModel: RFPInstreamInfoModel? = null
              
                  // ... ...
              
                  fun bindData(model: RFPInstreamInfoModel) {
                      adModel = model
                      // ... ...
                  }
              
                  // ... ...
              
                  override fun onClick(v: View?) {
                      // インプレッションの送信とLPへの遷移
                      RFPInstreamAdEvent.sendClickEvent(v.context, model)
                  }
              }
              

              インプレッションイベントの送信

              広告が視認可能となった時点でRFPInstreamAdEvent#measureImp()を呼びインプレッションを送信する必要があります。

              // インプレッションを送信する
              // 重複排除などは SDK が行っているため、毎回通信などは発生しない
              RFPInstreamAdEvent.measureImp(context, adModel);
              

              インプレッション送信のタイミングについて

              インプレッション送信のタイミングは広告が表示された時に行う必要がありますが、ユーザーが広告を視認可能にすることを保証するため、本SDKはアドビューアブルインプレッションを推奨します。

              本SDKではこれをサポートする RFPVisibilityTracker というクラスを提供しています。詳細については Viewable Impressionの実装 をご確認ください。