在Live Wallpaper设定中加入AdMob广告

By | 2011/09/14

自从Android 2.1中加入了动态壁纸,一下子牛叉了很多啊,漂亮的壁纸层出不穷,看上去老土的Android手机总算也是可以炫一下了。

动态壁纸基础

制作方法,网上太多了,虽然基本都是抄的,其实都是从sample上发展出来的,我也把要点记一下,每次写新的都要把老的工程打开看,啥记性……

  1. res/xml中指定动态壁纸的xml文件:
    <?xml version="1.0" encoding="utf-8"?>
    <wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
     android:settingsActivity="xxx.yyy.LiveWallpaperSettings"
     android:thumbnail="@drawable/icon" />

    这里是说明自己图标和设定Activity。

  2. 还有一个设定Activity的xml文件,就是普通的PreferenceScreen,省略。
  3. 创建WallpaperService的子类,需要再onCreateEngine方法中返回一个Engine,Engine中画画儿,就像用SurfaceView一样。 
    public class LiveWallpaper extends WallpaperService {
    	public static final String SHARED_PREFS_NAME = "setting_file_name";
    	@Override
    	public void onCreate() {
    		super.onCreate();
    	}
    	@Override
    	public void onDestroy() {
    		super.onDestroy();
    	}
    	@Override
    	public Engine onCreateEngine() {
    		return new TestPatternEngine();
    	}
    	class TestPatternEngine extends Engine implements
    			SharedPreferences.OnSharedPreferenceChangeListener {
    		private final Handler mHandler = new Handler();
    		private final Runnable mDrawPattern = new Runnable() {
    			public void run() {
    				drawFrame();
    			}
    		};
    		private boolean mVisible;
    		private SharedPreferences mPreferences;
    		TestPatternEngine() {
    			mPreferences = LiveWallpaper.this.getSharedPreferences(
    					SHARED_PREFS_NAME, 0);
    			mPreferences.registerOnSharedPreferenceChangeListener(this);
    			onSharedPreferenceChanged(mPreferences, null);
    		}
    		public void onSharedPreferenceChanged(SharedPreferences prefs,
    				String key) {
    		}
    		@Override
    		public void onCreate(SurfaceHolder surfaceHolder) {
    			super.onCreate(surfaceHolder);
    		}
    		@Override
    		public void onDestroy() {
    			super.onDestroy();
    			mHandler.removeCallbacks(mDrawPattern);
    		}
    		@Override
    		public void onVisibilityChanged(boolean visible) {
    			mVisible = visible;
    			if (visible) {
    				drawFrame();
    			} else {
    				mHandler.removeCallbacks(mDrawPattern);
    			}
    		}
    		@Override
    		public void onSurfaceChanged(SurfaceHolder holder, int format,
    				int width, int height) {
    			super.onSurfaceChanged(holder, format, width, height);
    			drawFrame();
    		}
    		@Override
    		public void onSurfaceCreated(SurfaceHolder holder) {
    			super.onSurfaceCreated(holder);
    		}
    		@Override
    		public void onSurfaceDestroyed(SurfaceHolder holder) {
    			super.onSurfaceDestroyed(holder);
    			mVisible = false;
    			mHandler.removeCallbacks(mDrawPattern);
    		}
    		@Override
    		public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
    				float yStep, int xPixels, int yPixels) {
    			drawFrame();
    		}
    		void drawFrame() {
    			final SurfaceHolder holder = getSurfaceHolder();
    			Canvas c = null;
    			try {
    				c = holder.lockCanvas();
    				if (c != null) {
    					// draw something
    				}
    			} finally {
    				if (c != null)
    					holder.unlockCanvasAndPost(c);
    			}
    			mHandler.removeCallbacks(mDrawPattern);
    			if (mVisible) {
    				mHandler.postDelayed(mDrawPattern, 1000 / 25);
    			}
    		}
    	}
    }
  4. 还有设定Activity的实现:
    public class LiveWallpaperSettings extends PreferenceActivity
        implements SharedPreferences.OnSharedPreferenceChangeListener {
        @Override
        protected void onCreate(Bundle icicle) {
            super.onCreate(icicle);
            getPreferenceManager().setSharedPreferencesName(LiveWallpaper.SHARED_PREFS_NAME);
            addPreferencesFromResource(R.xml.livewallpaper_settings);
            getPreferenceManager().getSharedPreferences()
                .registerOnSharedPreferenceChangeListener(this);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
        }
    
        @Override
        protected void onDestroy() {
            getPreferenceManager().getSharedPreferences()
                .unregisterOnSharedPreferenceChangeListener(this);
            super.onDestroy();
        }
    
        public void onSharedPreferenceChanged(
            SharedPreferences sharedPreferences, String key) {
        }
    }
  5. androidmanifest.xml中一定要加入的:
    <service android:name=".LiveWallpaper" android:label="@string/app_name"  android:icon="@drawable/icon">
        <intent-filter>
            <action android:name="android.service.wallpaper.WallpaperService" />
        </intent-filter>
        <meta-data android:name="android.service.wallpaper" android:resource="@xml/livewallpaper" />
    </service>
    
    <activity android:label="@string/livewallpaper_settings"
       android:name=".LiveWallpaperSettings"
       android:theme="@android:style/Theme.Light.WallpaperSettings"
       android:exported="true"
       android:icon="@drawable/icon">
    </activity>
    
    <uses-sdk android:minSdkVersion="7" />
    <uses-feature android:name="android.software.live_wallpaper" />

    “uses-feature android:name=”android.software.live_wallpaper””这句话要慎用啊!Google的电子市场会认这句话,然后把有些可以用的机器过滤掉,比如俺的破机器,本来是不支持的,升级到2.1按说是可以用的。我看了市场上很多有名的动态壁纸,就没有加这句话~~

另外,如果想在动态壁纸中使用OpenGL ES,请参考这篇文章:Android中使用OpenGL ES的一二事

加入AdMob广告

上面都是废话,我这次想说的主题是如何在壁纸设定界面里加入AdMob广告,好不容易做好的东西,总是要意思意思是吧,加个广告是没法的事情了。

不同于一般的Activity,直接加入AdMob是不行的,连个Layout都没有,而且直接加到壁纸上则非常糟糕,谁也不希望好好的背景上塞一个广告。所以一般动态壁纸的广告都加在设置界面里,这样还真有些不容易。

一般有两种方法,把Admob的adView当做一个Preference,直接加入xml就好。

public class AdmobPreference extends Preference {

    public AdmobPreference(Context context) {
        super(context, null);
    }

    public AdmobPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected View onCreateView(ViewGroup parent) {
        //override here to return the admob ad instead of a regular preference display
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        return inflater.inflate(R.layout.admob_preference, null);
    }

}

相对的admob_preference的配置:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/ad_layout"
    android:layout_width="fill_parent" android:layout_height="fill_parent">

    <com.google.ads.AdView
	    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
		android:id="@+id/ad"
		android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        ads.adSize="BANNER"
        ads:adUnitId="a14e51ca560d266"
        ads:loadAdOnCreate="true"
         />

</LinearLayout>

Android AdView missing required XML attribute "adsize"

这里还是有些学问的,网上查一下会有无数的“AdView missing required XML attribute ‘adSize’”的问题,据说是4.1.0之后带来的问题,一定要这么写(将”http://schemas.android.com/apk/lib/com.google.ads”当做一个命名空间,而不是加入自己的程序中)才能不出错,至少大家是如此说的,可惜我不行,怎么写都有这个错,耗费了两个小时尝试了各种写法,还是不行啊!!最后还是写在代码里了:(

不过光这么写貌似还是不行,AdView周围还有留白,貌似是PreferenceActivity里的padding,去不掉,最后还是使用了Tab的方式:

public class SettingsTabActivity extends TabActivity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.table_layout);

        TabHost tabHost = getTabHost();  // The activity TabHost
        TabHost.TabSpec spec;  // Resusable TabSpec for each tab
        Intent intent;  // Reusable Intent for each tab

        // Create an Intent for the regular live wallpaper preferences activity
        intent = new Intent().setClass(this, LivePaperSettings.class);

        // Initialize a TabSpec and set the intent
        spec = tabHost.newTabSpec("TabTitle").setContent(intent);
        spec.setIndicator("TabTitle");

        tabHost.addTab(spec);

        tabHost.setCurrentTab(0);    
    }

对应的layout:

<?xml version="1.0" encoding="utf-8"?>

<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
	android:id="@android:id/tabhost" android:layout_width="fill_parent"
	android:layout_height="fill_parent">

	<LinearLayout android:orientation="vertical"
		android:id="@+id/main_layout"
		android:layout_width="fill_parent" android:layout_height="fill_parent">

		<com.google.ads.AdView android:id="@+id/ad"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			ads:backgroundColor="#000000"
			ads:primaryTextColor="#FFFFFF"
			ads:secondaryTextColor="#CCCCCC"
			ads.adSize="BANNER"
			ads:adUnitId="a14e51ca560d266"
			ads:loadAdOnCreate="true" />

		<TabWidget android:id="@android:id/tabs"
			android:layout_width="fill_parent" android:layout_height="1dp"
			android:visibility="invisible" />

		<FrameLayout android:id="@android:id/tabcontent"
			android:layout_width="fill_parent" android:layout_height="fill_parent"
			android:padding="1dp" />
	</LinearLayout>
</TabHost>

大概就是如此了。

对了还有一个浪费了我两个多小时的问题,对于已经按照的live wallpaper,你修改了setting的Activity,直接覆盖安装是没效果的,点配置还是出现以前的Activity,发现这一点之前,我做了不知几百次修改上传,都快整挂了,Google怎么考虑的?!

6 thoughts on “在Live Wallpaper设定中加入AdMob广告

  1. 8888

    出现AdView missing required XML attribute ‘adSize’是因为ads:adSize=”BANNER”打错成ads.adSize=”BANNER” , 但不了解, 已按了方法使用. 但广告都出不来.

    Reply
  2. xishui Post author

    @8888: 传上来写错了……这种弱智错误Eclipse会告诉我的。。

    Reply
  3. iceman_22

    能把代码发给我吗?805858226@qq.com
    谢谢!

    Reply
  4. 1

    如果博主通过tabactivity间接的启动preferenceActivity,但是在wallperpar中那个设置acitivity只能是一个preference的activity!这个问题怎么解决呢!

    Reply
  5. 5555

    有可能在自己的activity中启动WallpaperService吗?

    Reply
  6. 网名无法显示

    感谢楼主的分享。楼主你不妨尝试下keymob平台。keymob平台支持的开发平台多、丰富多样化的广告形式、还有丰富的广告资源。并且还能顺利通过市场审核,还不用担心被封号。这些都是keymob平台的优势支持。你想了解更多的信息请登入keymob平台官网进行了解。平台地址:www.keymob.com

    Reply

5555进行回复 取消回复

您的电子邮箱地址不会被公开。