在实际工作中,经常遇到客户需要用代码设置系统时间的需求,但是Android非系统应用是无法设置系统时间的。于是,我设计了一个使用系统签名的时间设置服务,客户通过bind调用服务里的方法就能达到设置时间的目的。
这里用到的技术有:
1、Signapk签名
2、AIDL
3、bind service
将应用变成系统应用
1、AndroidManifest.xml中加入android:sharedUserId="android.uid.system"
2、使用系统密钥签名。系统签名在Android源码目录中的位置是"build argetproductsecurity",下面的platform.pk8和platform.x509.pem两个文件。然后用Android提供的Signapk工具来签名,signapk的源代码是在"build oolssignapk"下,用法为"signapk platform.x509.pem platform.pk8 input.apk output.apk"
时间设置服务 CustomServices
ICustomServices.aidl 里定义了设置日期和设置时间方法
1 interface ICustomServices { 2 3 void setDate(int year,int month,int day); 4 void setTime(int hourOfDay, int minute); 5 6 }
CustomService.Java
1 public class CustomService extends Service { 2 private static final String TAG = CustomService.class.getSimpleName(); 3 4 private MyBinder mBinder; 5 6 @Override 7 public void onCreate() { 8 super.onCreate(); 9 10 if (mBinder == null) { 11 mBinder = new MyBinder(); 12 } 13 14 } 15 16 17 @Override 18 public IBinder onBind(Intent intent) { 19 return mBinder; 20 } 21 22 23 class MyBinder extends ICustomServices.Stub { 24 25 @Override 26 public void setDate(int year, int month, int day) throws RemoteException { 27 28 setDate(CustomService.this, year, month - 1, day); 29 } 30 31 @Override 32 public void setTime(int hourOfDay, int minute) throws RemoteException { 33 setTime(CustomService.this, hourOfDay, minute); 34 } 35 36 void setDate(Context context, int year, int month, int day) { 37 Calendar c = Calendar.getInstance(); 38 39 c.set(Calendar.YEAR, year); 40 c.set(Calendar.MONTH, month); 41 c.set(Calendar.DAY_OF_MONTH, day); 42 long when = c.getTimeInMillis(); 43 44 if (when / 1000 < Integer.MAX_VALUE) { 45 ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); 46 } 47 } 48 49 void setTime(Context context, int hourOfDay, int minute) { 50 Calendar c = Calendar.getInstance(); 51 52 c.set(Calendar.HOUR_OF_DAY, hourOfDay); 53 c.set(Calendar.MINUTE, minute); 54 c.set(Calendar.SECOND, 0); 55 c.set(Calendar.MILLISECOND, 0); 56 long when = c.getTimeInMillis(); 57 58 if (when / 1000 < Integer.MAX_VALUE) { 59 ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); 60 } 61 } 62 } 63 64 }
AndroidManifest.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.rs.customservices" android:sharedUserId="android.uid.system"> 4 <application 5 android:allowBackup="true" 6 android:icon="@mipmap/ic_launcher" 7 android:label="@string/app_name" 8 android:supportsRtl="true" 9 android:theme="@style/AppTheme"> 10 11 12 <service 13 android:name="com.rs.customservices.CustomService" 14 android:enabled="true" 15 android:exported="true"> 16 <intent-filter> 17 <action android:name="com.rs.CustomService" /> 18 </intent-filter> 19 </service> 20 </application> 21 22 </manifest>
编译完后使用系统签名将APK文件签名成系统应用。
客户程序
将上面工程中的 ICustomServices.aidl 拷入到客户工程中,注意:包的目录结构也需要拷入。
CustomServiceActivity.java
1 public class CustomServiceActivity extends Activity { 2 private static final String TAG="CustomServiceActivity"; 3 4 ICustomServices mCustomServices; 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_custom_service); 9 10 Intent intentCust = new Intent(); 11 intentCust.setAction("com.rs.CustomService"); 12 //在5.0及以上版本必须要加上这个 13 intentCust.setPackage("com.rs.customservices"); 14 bindService(intentCust, mServiceConnection, Context.BIND_AUTO_CREATE); 15 } 16 17 ServiceConnection mServiceConnection = new ServiceConnection() { 18 @Override 19 public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 20 mCustomServices = ICustomServices.Stub.asInterface(iBinder); 21 22 Log.i(TAG,"mServiceConnection2 onServiceConnected"); 23 24 25 try { 26 mCustomServices.setDate(1999, 5,6); 27 mCustomServices.setTime(5,45); 28 } catch (RemoteException e) { 29 e.printStackTrace(); 30 } 31 32 } 33 34 @Override 35 public void onServiceDisconnected(ComponentName componentName) { 36 37 } 38 }; 39 40 41 @Override 42 protected void onDestroy() { 43 super.onDestroy(); 44 unbindService(mServiceConnection); 45 } 46 }