OpenAdAdapter-簡単なモバイル広告管理

数年前、1つの広告ネットワークをモバイルアプリケーションに挿入するだけでは不十分であるため、いくつかのネットワークを追加することにしました。この冬、この開発を書き直してgithubに配置することにしました。 そこで、OpenAdAdapterが誕生しました。



OpenAdAdapterは、モバイルゲーム(AndroidおよびiOS、Apache 2.0ライセンス)用のライブラリです。 APIを簡単にするために、すべてのアプリケーション用ではなく、ゲーム用のアダプターを作成することにしました。 ゲームとは、画面全体に1つのGLキャンバスがあり、バナーが上または下にあるアプリケーションを意味します。 バナーがある場合、キャンバスを少し移動する必要があります。 つまり、開発者は単に、Xをネットワークに入れる方法を詳しく調べる必要なく、下のバナーを表示するだけです。 多くのゲームは、SDKおよびMarmaladeやUnityなどのエンジンを使用して開発されています。 そこで、ネイティブプラットフォームに到達し、コールバックの実装のすべてのニュアンスを調査するために、これは独立した実務です。 ところで、これがまさにOpenAdAdapterにコールバックがない理由です。



OpenAdAdapter APIは任意のスレッドから呼び出すことができると想定されています。 (私はそう思いましたが、約束するのが怖いです)。 すべてのメソッドは静的です。



現在、次のネットワークがサポートされています。



Android


-AdColony

-admmob

-AerServ

-Chartboost

-heyzap

-InMobi



iOS


-AdColony

-admmob

-AerServ

-Chartboost

-heyzap

-InMobi

-iAd



新しいネットワーク用のアダプターの作成は簡単です。 最初はロシアのWapStartをサポートし、モスクワのトラフィックに対して2日間、クリックあたり1ドルの信じられないほどの金額(通常5セント)を支払った後、30%の罰金を科してお金を与えましたが、それらを追加するとAndroidのすべてが複雑になります。 事実は、すべてのネットワークが統合用のjarファイルを提供し、WapStartがプロジェクトにリソースファイルも含めてEclipseを提供したことです。 そのため、まだ実装していません。



設定は、インターネットからJSONファイルからダウンロードされます。



OpenAdAdapter.initFromUrl( this, "https://raw.githubusercontent.com/sample-data/oad1/master/android-redirect.json");
      
      







  [OpenAdAdapter startWithUrl:@"https://raw.githubusercontent.com/sample-data/oad1/master/ios-redir.json"];
      
      







(githubで静的ファイルをホストすると、githubの規則に違反する場合があります)



これは非常に重要です。 一部のネットワークで戦略を変更したり、広告の表示を停止したりできます。または、一部のネットワークで禁止される場合があります。



OpenAdAdapterは、上または下からバナーを表示したり、バナーを非表示にしたり、フルスクリーン(フルスクリーン/インタースティシャル)で広告を表示したり、ビデオ(ビデオ)および有料ビデオ(報酬)を表示したりできます。 何をどのように表示するかは、jsonファイルに記述されています。



iOS



iPhone用コントローラー
 #import "ViewController.h" #import "OpenAdAdapter.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIButton *btnInit; @property (weak, nonatomic) IBOutlet UILabel *label1; @end @implementation ViewController { bool btick; NSString * rewardText; } - (IBAction)clickChkReward:(id)sender { OADReward * reward = [OpenAdAdapter reward]; if(reward != nil){ self->rewardText = [NSString stringWithFormat:@"%@ %f %@", [reward network], [reward amount], [reward currency]]; }else{ self->rewardText = @""; } } - (IBAction)clickInit:(id)sender { if(!self->btick){ self->btick = true; [self performSelector:@selector(tick) withObject:nil afterDelay:1.0]; } self.label1.text = @"Initializing 1"; [OpenAdAdapter startWithUrl:@"https://raw.githubusercontent.com/sample-data/oad1/master/ios-redir.json"]; // [OpenAdAdapter startWithUrl:@"https://raw.githubusercontent.com/sample-data/oad1/master/ios-no-heyzap.json"]; //[OpenAdAdapter startWithUrl:@"https://raw.githubusercontent.com/sample-data/oad1/master/ios-heyzap.json"]; self.label1.text = @"Initializing 2"; } -(void)tick{ [self performSelector:@selector(tick) withObject:nil afterDelay:1.0]; NSString * s1 = [NSString stringWithFormat:@"bh %g %g %@", [OpenAdAdapter bannerHeightPts], [OpenAdAdapter bannerHeightPixels], self->rewardText]; self.label1.text = s1; } - (IBAction)clickBanner:(id)sender { [OpenAdAdapter showTopBanner:self]; } - (IBAction)clickBottomBanner:(id)sender { [OpenAdAdapter showBottomBanner:self]; } - (IBAction)clickHideBanner:(id)sender { [OpenAdAdapter hideBanner]; } - (IBAction)clickFullscreen:(id)sender { [OpenAdAdapter showFullscreen:self]; } - (IBAction)clickVideo:(id)sender { [OpenAdAdapter showVideo:self]; } - (IBAction)clickRewarded:(id)sender { [OpenAdAdapter showRewarded:self]; } - (IBAction)clickTest:(id)sender { // [TestX1 test1]; [OpenAdAdapter test1]; } - (IBAction)clickTest2:(id)sender { //[OpenAdAdapter test2:self]; [OpenAdAdapter showTopBanner:self]; } - (IBAction)clickTest3:(id)sender { //[OpenAdAdapter test3:self]; [OpenAdAdapter showBottomBanner:self]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
      
      







iOS用アプリケーションのリンク(Androidから)の違いにより、各ネットワークに1つのlibではなく、1つの+アダプターを作成する必要がありました。

つまり、Chartboostが必要な場合は、プロジェクトに追加する必要があります



-libOADAdapterChartboost.a-OpenAdAdapterのアダプター

-Chartboost.framework-オリジナルのChartboostフレームワーク



github.com/OpenAdAdapter/OAD-iOS-bin/tree/master/chartboost



-libOpenAdAdapter.a-およびOpenAdAdapter自体



最も簡単なことは、すべてのネットワークを一度にスローすることです。



github.com/OpenAdAdapter/OAD-iOS-bin



必要なフレームワークを追加します。



  AdSupport.framework StoreKit.framework MessageUI.framework libxml2.2.dylib libz.dylib libsqlite3.0.dylib CoreTelephony.framework EventKit.framework EventKitUI.framework Security.framework Social.framework WebKit.framework
      
      







およびその他のリンカーフラグ:-ObjC



Android



例のアクティビティ
 package com.example.testoad01; import com.openadadapter.OpenAdAdapter; import com.openadadapter.Reward; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends ActionBarActivity { Runnable tick = new Runnable(){ @Override public void run() { try{ label1.setText("bh " + OpenAdAdapter.getBannerHeightInPoints() + " " +OpenAdAdapter.getBannerHeightInPixels()); } finally{ handler.postDelayed(tick, 1000); } }}; Handler handler = new Handler(Looper.getMainLooper()); boolean ticking; private TextView label1; @Override protected void onCreate(Bundle savedInstanceState) { // TestX.test(); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); OpenAdAdapter.onCreate(this); label1 = (TextView)findViewById(R.id.textView1); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void butBS(View v) { Toast.makeText(getApplicationContext(), "Bottom Banner Show", Toast.LENGTH_LONG).show(); OpenAdAdapter.showBottomBanner(null); } public void butBSTop(View v) { Toast.makeText(getApplicationContext(), "Top Banner Show", Toast.LENGTH_LONG).show(); OpenAdAdapter.showTopBanner(null); } public void butBH(View v) { Toast.makeText(getApplicationContext(), "Banner Hide", Toast.LENGTH_LONG).show(); OpenAdAdapter.hideBanner(); } public void butF(View v) { Toast.makeText(getApplicationContext(), "Banner Fullscreen", Toast.LENGTH_LONG).show(); OpenAdAdapter.showFullscreen(null); } public void butVideo(View v) { Toast.makeText(getApplicationContext(), "Banner Video", Toast.LENGTH_LONG).show(); OpenAdAdapter.showVideo(null); } public void butR(View v) { Toast.makeText(getApplicationContext(), "Rewarded Video", Toast.LENGTH_LONG).show(); OpenAdAdapter.showRewarded(null); } public void butIU(View v) { Toast.makeText(getApplicationContext(), "Init from URL", Toast.LENGTH_LONG).show(); // OpenAdAdapter.initFromUrl(this, // "https://raw.githubusercontent.com/sample-data/oad1/master/data1.json"); OpenAdAdapter .initFromUrl( this, "https://raw.githubusercontent.com/sample-data/oad1/master/android-redirect.json"); if(!ticking){ handler.postDelayed(tick, 1000); ticking = true; } } public void butIF(View v) { Toast.makeText(getApplicationContext(), "Init from File", Toast.LENGTH_LONG).show(); // OpenAdAdapter.preinit(); } public void butV(View v) { Toast.makeText(getApplicationContext(), "verify", Toast.LENGTH_LONG) .show(); OpenAdAdapter.verify(); } public void butSF(View v) { Toast.makeText(getApplicationContext(), "Show Fullscreen", Toast.LENGTH_LONG).show(); OpenAdAdapter.showMyFullscreen(this); } public void clickFetchReward(View v) { Reward reward = OpenAdAdapter.fetchReward(); if (reward == null) { Toast.makeText(getApplicationContext(), "No reward", Toast.LENGTH_LONG).show(); } else { Toast.makeText( getApplicationContext(), "Reward " + reward.getNetwork() + " " + reward.getAmount() + " " + reward.getCurrency(), Toast.LENGTH_LONG) .show(); } } @Override public void onStart() { super.onStart(); OpenAdAdapter.onStart(this); } @Override public void onResume() { super.onResume(); OpenAdAdapter.onResume(this); } @Override public void onPause() { super.onPause(); OpenAdAdapter.onPause(this); } @Override public void onStop() { super.onStop(); OpenAdAdapter.onStop(this); } @Override public void onDestroy() { super.onDestroy(); OpenAdAdapter.onDestroy(this); } @Override public void onBackPressed() { if (OpenAdAdapter.onBackPressed(this)) return; super.onBackPressed(); } }
      
      







一部のネットワークではonStart、onPause、onResumeなどの通知を受信する必要があるため、これらのイベント中にAndroidのOpenAdAdapterを呼び出す必要があります。



また、 AndroidManifest.xmlで指定する必要があるアクティビティの山についても忘れないでください。



そして、すべてのjarファイルをlibフォルダーに捨てます(不要なものは捨てることができます): github.com/OpenAdAdapter/OAD-Android-bin/tree/master/lib



自明-ありそう



重要な点:バナーがプログラムインターフェイスと重なることは望ましくありません。 プロジェクトの作成を促したのはこの問題でした。 私のアプリケーションは、デリゲート/コールバック/リスナーが報告する内容に基づいてバナーがあるかどうかを判断しました。



-AdShown-縮小された画面

-AdFailed-画面はリラックスしています



つまり、画面のスクリーンショットを撮らず、バナーの画像を認識しませんでしたが、最高の広告ネットワークが期待どおりに機能しないことがわかりました。 彼女はAdFailedを伝えることができ、アプリケーションがキャンバスを全画面に展開するとき-アプリケーションを禁止します。



次の機能がコンテンツの重複の問題の解決策になりました



 int pt = OpenAdAdapter.getBannerHeightInPoints(); int px = OpenAdAdapter.getBannerHeightInPixels();
      
      





 int pt = [OpenAdAdapter bannerHeightPts]; int px = [OpenAdAdapter bannerHeightPixels];
      
      





値0がバナーなしの場合、0より大きい値は上のバナー、0より小さい値は下のバナーです。 各フレームまたは1秒に1回呼び出して、それに応じてGLキャンバスの寸法を変更できます。



コールバックを使用しない同様の方法で 、リワード動画を視聴するためのリワードチェックを実装することにしました。



JSON構成ファイル



raw.githubusercontent.com/sample-data/oad1/master/data1.json



 { "debug":{"verify":true}, "urls":["https://ohohoho.appspot.com/track", {"url":"https://xman545476.appspot.com/track", "priority": 10}], "commands":["save", {"cmd":"settings", "settings":{"reportLocation":true, "advertisingId":true, "userId": true}}], "strategy":{ "banner": {"list":["admob", "inmobi", "wapstart", "aerserv"], "strategy":"random"}, "fullscreen2": { "list":[ "aerserv", "inmobi"], "strategy":"random"}, "fullscreen": { "list":[ "aerserv", "heyzap", "adcolony", {"name":"heyzap","type":"rewarded", "preload": "always"}, "admob", {"name":"chartboost","type":"video", "preload": "low"}, "inmobi"], "strategy":"random"}, "video": {"list":["chartboost", "heyzap"],"strategy":"round-robin"}, "rewarded": {"list":["adcolony", "chartboost", "heyzap"], "strategy":"random"} }, "networks":[ { "name":"admob", "bannerId":"ca-app-pub-8607147313123654/8458359243", "fullscreenId":"ca-app-pub-8607147313123654/9935092440" }, { "name":"inmobi", "propId":"d4783f2efd4147499e40cc3540f2d221", "bannerId":"d4783f2efd4147499e40cc3540f2d221", "fullscreenId":"d4783f2efd4147499e40cc3540f2d221", "bannerId1":"1428178968194889", "fullscreenId1":"1428178928625995" }, { "name":"chartboost", "id":"5519c460c909a67c4e1e58a4", "sig":"e34adc93d56dfcff2a3a34d5f0dcd74204cbaf05", "video": "true", "rewarded": "true" }, { "name":"heyzap", "id":"e0c44b21d39c921a55f31ea836a70b65", "video": "true", "rewarded": "true" }, { "name":"adcolony", "id":"app398cb71e4cae463f94", "videoId":"vzc71a58270b924c95a0", "rewardedId":"vz6669f90f9dbe4e4a89" }, { "name":"aerserv", "fullscreenId":"1000741", "banner320":"1000834", "banner728":"1000835" }, { "name":"home", "bannerId":"", "halfId":"", "fullscreenId":"" }, { "name":"direct", "bannerId":"", "halfId":"", "fullscreenId":"" } ] }
      
      





最初の3つのキーdebug、urls、commandsはまだ使用されていません。 ネットワークキーはネットワークをリストします。 最後の2つ(自宅、直接)もまだ使用されていません。 JSONファイルよりもインテリジェントなサーバーを開発しています。



この構成では、戦略キーが最も困難です。 彼は4つの戦略-バナー、フルスクリーン、ビデオ、リワードの4つのサブキーを持っています。

(fullscreen2-使用されません)



 "banner": {"list":["admob", "inmobi", "wapstart", "aerserv"], "strategy":"random"}
      
      





各戦略には、リストと戦略という2つのキーがあります。



-リスト-ネットワークをリストします。

-戦略-戦略を定義します:ランダム、ラウンドロビン、フェールセーフ。



ランダム-広告をランダムに表示します。

ラウンドロビン-広告を順番に表示します。

フェイルセーフ-リストの最初の広告を常に表示し、機能しない場合は2番目の広告を表示します。



このファイルを作成するHTMLアプリケーションを作成しました。 すぐに投稿します。



プロジェクトの展開方法



HTML-構成を編集するためのアプリケーション(既に作成済み)。

Webサイト-開発者がネットワークを選択し、ZIPファイル(すべてが含まれており、1回の動きでプロジェクトに簡単にコピーできる)と、追加するフレームワークとAndroidManifest.xmlで記述する内容に関する指示を受け取るように、Webサイトを作成する予定です。

Unity3D-両方のプラットフォームですべてのタイプの広告を表示するように書かれていますが、そこではそれほど単純ではなく、実装の説明には別の記事が必要ですが、UnityAdsはサポートされていません。

サーバー-多くのアイデアがあり、無限に開発できます。

チューニング-画面に対するバナーのサイズ、ネットワークのスマートで経済的なプリロードなど。

セルフテスト-Androidプロジェクトでは、verifyメソッドを確認できます。 理論的には、必要なすべてのアクティベーション、パーミン、レシーバー、およびGoogle Playサービスバージョンのメタタグが定義されているかどうかを確認する必要があります。 そして彼は部分的にそれを行いますが、最後までこの機能は実装されていません。

Megamindに関する記事-Mopub、AdTapsy、Appodeal、および信じられないほどのCTRを約束する他の人に対してOpenAdAdapterを使用するビジネスケース。



All Articles