最近做项目的时候,收到客户的需求,说是创建一个获取系统属性服务,并且开机自启动,需求本身不难,代码量一个不高,但是有几个关键点:1、开机自启动 2、系统服务(需要用到AIDL进行数据传输);拿到需求的第一步准备下手的是开机自启动。
一、开机自启动
这里要分三步走:
第一步:加入开机自启动权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
第二步:注册广播接收器
<receiver android:name=".MyReceiver">
<intent-filter android:priority="4000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
android:priority是启动优先级,值越大优先级越高,所以这里根据自己的情况而定。
MyReceiver源码
public class MyReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
Log.i(StbService.TAG, "boot receiver");
Intent i = new Intent(context, StbService.class);
context.startService(i);
}
}
}
第三步:将当前当前应用生成的apk复制到system/app下,如果含有.so文件,需要复制到system/lib目录下。有很多平台开机自启动不需要将应用复制到system/app下,直接安装就可以,
这个具体原因不清楚。
以上三步就是实现开机自启动的步骤。
二、搭建系统服务一个完整的系统服务
需要分为通信AIDL、服务器端、客户端
1、创建你要传递数据的AIDL文件
AIDL是android接口定义语言,常用于进程间通信,它是一种轻量级通信语言,它能传递基本的数据类型或者带基本数据类型的List,其他情况的类都需要通过
序列化。这里要注意,服务器端和客户端的AIDL文件必须一样,且必须在相同的包名下。
代码如下:
package com.konka.qosmonloader.aidl;
interface IStbParmService{
String getStbParameter(String parmName);
}
上面的aidl会生成相应的Binder,
因为sub类实现了Binder接口,所以以后会使用这个类。
2、创建服务器端代码StbService
Stbservice.java实现如下:
public class StbService extends Service {
public static final String TAG = "StbService";
private String Account = "ServerID";
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "StbService start");
return super.onStartCommand(intent, flags, startId);
}
private final IStbParmService.Stub binder = new IStbParmService.Stub() {
public static final String TAG = "IRemoteService.Stub";
@Override
public String getStbParameter(String parmName) throws RemoteException {
String parmValue = "";
if ("Account".equals(parmName)) {
parmValue = Account; // 业务账号。
}
return parmValue;
}
};
}
对应的服务器端清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.konka.qosmonloader"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<permission android:name="thomas.permission.AIDL_SERVICE"/>
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity android:name="com.konka.qosmonloader.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.konka.qosmonloader.StbService"
android:label="StbService"
android:enabled="true"
android:exported="true"
android:process=":remote"
android:permission="thomas.permission.AIDL_SERVICE">
<intent-filter>
<action android:name="com.certus.ottstb.bestv.StbParmService"/>
</intent-filter>
</service>
<receiver android:name=".MyReceiver">
<intent-filter android:priority="4000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</manifest>
特别注意:
1、需要加入权限<permission android:name="thomas.permission.AIDL_SERVICE"/> 2、自定义命名一个action,供客户端访问
我这里命名为<action android:name="com.certus.ottstb.bestv.StbParmService"/>这个名字可以随便命名,但是客户端过滤的
action必须同名。
服务器端的目录结构如下:
3、创建客户端Activity
目录结果如下:
MainActivity.java代码
public class MainActivity extends Activity {
private IStbParmService myService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent=new Intent("com.certus.ottstb.bestv.StbParmService");
this.getApplicationContext().bindService(intent, conn, BIND_AUTO_CREATE);
}
private ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
myService=null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
myService=IStbParmService.Stub.asInterface(service);
try {
String a = myService.getStbParameter("Account");
Toast.makeText(MainActivity.this, a, Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}
这里需要注意:注册用的action要跟前面提到的自己命名的action一样
接下来是清单文件的代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.aidltest"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="thomas.permission.AIDL_SERVICE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.aidltest.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
同样也要加入权限<uses-permission android:name="thomas.permission.AIDL_SERVICE"/>
以上是我这次创建一个开机自启动的Android系统服务的总结,代码是简化版的代码