I have been researching for a while and to include Admob into my Android game made with Adobe Air and I stumbled over this article from James Ward. He describes actually the most important steps to have everything setup.
So as soon as you have done the steps to set everything up as stated in James Ward article (to the point where it says System Notifications and Services), you can start following the steps here to have your admob add running in your game or app.
1. Create the Notification Service in Java
First of all create a java class called NotificationService. The class is also copied over from James Ward article with slight changes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | package com.roughsea; // This code is copied form James Ward article Extending Air for Android and change slightly // http://www.jamesward.com/2011/05/11/extending-air-for-android/ import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.Looper; import android.util.Log; public class NotificationService extends Service { public static MainApp app; private boolean stopped=false; private Thread serverThread; private ServerSocket ss; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Log.d(getClass().getSimpleName(), "onCreate"); serverThread = new Thread(new Runnable() { public void run() { try { Looper.prepare(); ss = new ServerSocket(12345); ss.setReuseAddress(true); ss.setPerformancePreferences(100, 100, 1); while (!stopped) { Socket accept = ss.accept(); accept.setPerformancePreferences(10, 100, 1); accept.setKeepAlive(true); DataInputStream _in = null; try { _in = new DataInputStream(new BufferedInputStream(accept.getInputStream(),1024)); } catch (IOException e2) { e2.printStackTrace(); } int id =_in.readInt(); // this depends on what your flash code is sending if (id == 1) { doNotification(_in); } } } catch (Throwable e) { e.printStackTrace(); Log.e(getClass().getSimpleName(), "Error in Listener",e); } try { ss.close(); } catch (IOException e) { Log.e(getClass().getSimpleName(), "keep it simple"); } } },"Server thread"); serverThread.start(); } private void doNotification(DataInputStream in) throws IOException { String task = in.readUTF(); String showAdd = "on"; if (task.equals(showAdd)) { app.showAd(); } else { app.removeAd(); } } public void setApp(MainApp _app) { app = _app; } @Override public void onDestroy() { stopped=true; try { ss.close(); } catch (IOException e) {} serverThread.interrupt(); try { serverThread.join(); } catch (InterruptedException e) {} } } |
2. Create the AS3 code for communication with the service
Include this function wherever it fits your needs in your flash code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// private function ToggleAdd(_show:Boolean):void { var text:String = "on"; if (_show == false) text = "off"; var s:Socket = new Socket(); s.connect("localhost", 12345); s.addEventListener(Event.CONNECT, function(event:Event):void { (event.currentTarget as Socket).writeInt(1); (event.currentTarget as Socket).writeUTF(text); (event.currentTarget as Socket).flush(); (event.currentTarget as Socket).close(); }); s.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent):void { trace('error! ' + event.errorID); }); s.addEventListener(ProgressEvent.SOCKET_DATA, function(event:ProgressEvent):void { trace('progress '); }); } |
The port 12345 is actually selected by random, you should just get sure you are using one which is not used anywhere else. I use the text sending for just switching things on or off as an example, but you could actually send any specific data.
You have now setup communication between flash and your android app. Now Change your MainApp.java like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | package com.roughsea; import air.app.AppEntry; import android.os.Bundle; import android.os.Message; import android.content.Intent; import com.google.ads.AdRequest; import com.google.ads.AdView; import com.google.ads.AdSize; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; import android.os.Handler; public class MainApp extends AppEntry { private static String MY_AD_UNIT_ID = "use your own ad unit id here"; private AdView adView = null; private MainApp app; @Override public void onCreate(Bundle arg0) { try { app = this; NotificationService.app = this; Intent srv = new Intent(this, NotificationService.class); startService(srv); } catch (Exception e) { // service could not be started } super.onCreate(arg0); } public void showAd() { handler.sendEmptyMessage(0); } public void removeAd() { handler.sendEmptyMessage(1); } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 0) { if (adView == null) { FrameLayout.LayoutParams adsParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.TOP|Gravity.CENTER_HORIZONTAL ); adView = new AdView(app, AdSize.BANNER, MY_AD_UNIT_ID); app.addContentView(adView, adsParams); AdRequest request = new AdRequest(); request.addTestDevice(AdRequest.TEST_EMULATOR); request.addTestDevice("0299D8EE8828629D2B15162000A09DE9"); adView.loadAd(request); } else { adView.setVisibility(View.VISIBLE); } } else if (msg.what == 1) { adView.setVisibility(View.INVISIBLE); } } }; } |
3. You want to place your ad somewhere else, no Problem!
1 2 3 4 5 | FrameLayout.LayoutParams adsParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.TOP|Gravity.CENTER_HORIZONTAL ); |
Just change the Gravity parameters to your needs. You can find a explanation of those parameters here
4. Now we need to setup the manifest file.
Load the AndroidManifest.xml file into your editor. You might have done some changes already when following James Ward article, but there are still things missing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?xml version="1.0" encoding="utf-8"?> <manifest package="com.roughsea" android:versionCode="1000000" android:versionName="1.0.0" xmlns:android="http://schemas.android.com/apk/res/android"> <application android:label="app" android:icon="@drawable/icon"> <activity android:theme="@style/Theme.NoShadow" android:background="@null" android:label="app" android:name=".MainApp" android:launchMode="singleTask" android:screenOrientation="nosensor" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="stateHidden|adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="aspectRatio" android:value="landscape" /> <meta-data android:name="autoOrients" android:value="false" /> <meta-data android:name="fullScreen" android:value="true" /> </activity> <activity android:name="com.google.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation"/> <receiver android:name="com.admob.android.ads.analytics.InstallReceiver" android:exported="true"> <intent-filter> <action android:name="com.android.vending.INSTALL_REFERRER" /> </intent-filter> </receiver> <service android:enabled="true" android:name=".NotificationService" /> </application> <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> </manifest> |
The following three lines are necessary if you want to have a landscape orientation pinned as well as fullscreen mode enabled. Change those parameters to your needs:
1 2 3 | <meta-data android:name="aspectRatio" android:value="landscape" /> <meta-data android:name="autoOrients" android:value="false" /> <meta-data android:name="fullScreen" android:value="true" /> |
If your compiler does not find that style android:theme=”@style/Theme.NoShadow”, open the values directory under res in your project and load styles.xml
Add the following code to your styles.xml if its missing:
1 2 3 4 5 6 | <resources> <style name="Theme.NoShadow" parent="@android:style/Theme.NoTitleBar"> <item name="android:windowContentOverlay">@null</item> <item name="android:windowNoTitle">true</item> </style> </resources> |
5. You are done…sort of
You should be ready now. First of all compile your swf, if you use the packager, it will build a apk file, which can be opened with any unzip tool. Go to the asset folder and copy the .swf into the asset folder of your project and rename it to app.swf
Compile your java android project and start the emulator. If you did everything right, you will see a test ad popping up in your flash app or game.
Dont forget to remove the addTestDevice codelines before uploading your app to the android market.
Closing thoughts
There are many android device and I have tested this code only an a Samsung Galaxy 9000S, but actually it should work on any other device. I hope I haven’t forgotten anything important. The code should work, I pasted from the original project and did only make some string adjustments. Please let me know if you run into any problems and I will try to help as far as I can.
I have no proof yet, if this fixed the account fraud problems, but I am quite sure, because the standard google admob API is used. We should be on the safe side here. You are actually not limited to admob, you could add any other advertisement API if its available for android.
Thats its for now. I hope somebody finds this helpful.