应用获取时间戳异常后通过系统应用修改时间
来源:互联网 发布:windows.iso怎样安装 编辑:程序博客网 时间:2024/06/11 00:46
一 综述
Android平台上面一个应用需要获取平台的系统时间作为时间戳,但是有时候系统启动的时候会将时间恢复到1970年~~这个初始时间,因此会导致应用和服务器之间的连接异常,因此有必要通过修改系统时间来解决这种启动异常导致的问题,但是修改Android系统时间是需要系统权限的,一般的应用层APP无法满足这个要求,不过,幸好能够在源码平台进行编译,因此主要的思路就是应用层APP启动异常之后通过广播通知在后台运行的一个系统应用(其实就是一个service)进行系统时间的修改,完成之后再通过广播告知应用层APP,系统时间修复成功,最后再应用层的APP重新获取时间戳登录服务器。整个思路比较明朗的,但是由于涉及到系统应用的编译等问题,结果前后折腾了一天才完成。
二 应用层广播
当系统启动异常之后,登录服务器失败,随即发出广播:
测试工程中的代码
public class MainActivity extends AppCompatActivity { public static final String ACTION_GET_NET_TIME_TO_SET_SYSTEM_TIM = "ACTION_GET_NET_TIME_TO_SET_SYSTEM_TIM"; private Button send; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); send = (Button)findViewById(R.id.send); send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { sendBroadcastToSystemTimeSetAPP("TEST"); } }); } /** * function: send broadcast to systemtimeset APP to test. * * */ public void sendBroadcastToSystemTimeSetAPP(String message){ //发送广播 String broadcastIntent = ACTION_GET_NET_TIME_TO_SET_SYSTEM_TIM; Intent intent = new Intent(broadcastIntent); intent.putExtra("MESSAGE", message); MainActivity.this.sendBroadcast(intent); }}
二 系统应用的编写
由于普通APP并没有修改系统时间的权限,因此专门写了一个应用在源码环境进行编译,主要工作就是在后台运行的service等待应用层广播去进行网络事件的获取和系统时间的修改。
通过一个activity来启动service,使用的是ServiceConnection,应为这样可以直接调用service里面的方法:
public class MainActivity extends Activity { public static Handler mReceiveTimeSetHandler; private GetNetTimeToSetSystemTimeService.TimeToSetBinder mTimeToSetBinder; private Context mContext; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mTimeToSetBinder = (GetNetTimeToSetSystemTimeService.TimeToSetBinder)iBinder; } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; //bind service Intent bindServiceIntent = new Intent(this, GetNetTimeToSetSystemTimeService.class); boolean isBind = bindService(bindServiceIntent, mServiceConnection, this.BIND_AUTO_CREATE); mReceiveTimeSetHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: mTimeToSetBinder.requireSetSystemTime(mContext); break; default: break; } } }; } @Override protected void onResume() { super.onResume(); //启动service之后退至后台 boolean movetoback = moveTaskToBack(true); }}
注意在启动成功之后,就将应用的activity退至后台,即在onResume里面进行处理。
关于service的分析,或者service的启动,郭琳大神的博客讲的非常清楚细致。
然后是service部分的代码,这部分里面我通过线程去获取了网络时间,获取和修改成功之后,直接在内部类里面发出了时间修改完成的广播:
public class GetNetTimeToSetSystemTimeService extends Service { public TimeToSetBinder mTimeToSetBinder = new TimeToSetBinder(); @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return mTimeToSetBinder; } public class TimeToSetBinder extends Binder{ private Handler mDataHandler; public void requireSetSystemTime(final Context context){ new Thread(new WebsiteDataDeal()).start(); mDataHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 1: String mTimeValue = (String) msg.obj; if (mTimeValue.length() == 19){ String[] temp = mTimeValue.split("\\s+"); String[] mYearMonthData = temp[0].split("-"); int year = Integer.valueOf(mYearMonthData[0]); int month = Integer.valueOf(mYearMonthData[1]); int day = Integer.valueOf(mYearMonthData[2]); String[] mHourMinuteSecond = temp[1].split(":"); int hour = Integer.valueOf(mHourMinuteSecond[0]); int minute = Integer.valueOf(mHourMinuteSecond[1]); int second = Integer.valueOf(mHourMinuteSecond[2]); setSysDate(context, year, month-1, day); setSysTime(context, hour, minute);// setSysDate(context, year, 10, 12);// setSysTime(context, hour, 22); sendBroadcastToXiaoLeRobot(context, "already set"); } break; default: break; } } }; } /** * function: send broadcast to XiaoLeRobot that system time already set. * * */ public void sendBroadcastToXiaoLeRobot(Context context, String message){ //发送广播 String broadcastIntent = Constants.ACTION_SYSTEM_TIM_ALREADY_SET; Intent intent = new Intent(broadcastIntent); intent.putExtra("MESSAGE", message); context.sendBroadcastAsUser(intent, UserHandle.ALL); } class WebsiteDataDeal implements Runnable{ @Override public void run() { String data = getNetWorkTime();// String websiteData = String.valueOf(data); mDataHandler.obtainMessage(1, data).sendToTarget(); } } public String getNetWorkTime(){ String format = "--"; URL url = null;//取得资源对象 long ld = 0; try { url = new URL("http://www.baidu.com"); URLConnection uc = url.openConnection();//生成连接对象 uc.connect(); //发出连接 ld = uc.getDate(); //取得网站日期时间 DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(ld); format = formatter.format(calendar.getTime()); } catch (Exception e) { e.printStackTrace(); } return format; } /** * 设置系统日期 * */ public void setSysDate(Context mContext, int year, int month, int day){ Calendar c = Calendar.getInstance(); c.set(Calendar.YEAR, year); c.set(Calendar.MONTH, month); c.set(Calendar.DAY_OF_MONTH, day); long when = c.getTimeInMillis(); if(when / 1000 < Integer.MAX_VALUE){ ((AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE)).setTime(when); } } /** * 设置系统时间 * */ public void setSysTime(Context mContext, int hour, int minute){ Calendar c = Calendar.getInstance(); c.set(Calendar.HOUR_OF_DAY, hour); c.set(Calendar.MINUTE, minute); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); long when = c.getTimeInMillis(); if(when / 1000 < Integer.MAX_VALUE){ ((AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE)).setTime(when); } } }}
这里有几个问题需要注意:1.设置时间的时候,出现一个问题,month的值必须减去1,不知道为啥,参见这篇文章的时候发现的:month要减去1
2.在这个地方发送的广播,由于是Android4.4的系统,sendBroadcast(intent)要写为sendBroadcastAsUser(intetn, UserHandler.ALL);具体情况请参见:sendBroadcastAsUser
好了,最后里面的时间修改参考了文章:
系统时间修改-参考settting源码
再加上一个开机启动的广播:
public class PowerBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(ACTION_BOOT_COMPLETED)){ // 启动应用首界面 Intent actIntent = new Intent(context.getApplicationContext(), MainActivity.class); actIntent.setAction("android.intent.action.MAIN"); actIntent.addCategory("android.intent.category.LAUNCHER"); actIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(actIntent); } }}
代码主要逻辑就是上述情况。
三 源码环境下编译配置
在源码下编译首先要在对应方案里面进行APP的配置,在对应方案目录下找到~~~.mk文件,并在里面加入: PRODUCT_PACKAGES += \
systemtimeset
然后在android/packages/apps/下面建立文件夹(工程包),编写Android.mk文件,由于这个应用很简单,并没有jar包和so等共享库文件,内容如下:
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-subdir-java-files)LOCAL_PACKAGE_NAME := systemtimesetLOCAL_CERTIFICATE := platformLOCAL_PROGUARD_ENABLED := disabledinclude $(BUILD_PACKAGE)include $(call all-makefiles-under,$(LOCAL_PATH))
需要注意的是,如果没有加入“include
四 应用层广播接收重新连接服务器
在应用层发出广播之后就等待系统应用返回设置成功后的广播:
public class ReceiveTimeSetInfo extends BroadcastReceiver { public static final String ACTION_SYSTEM_TIM_ALREADY_SET = "ACTION_SYSTEM_TIM_ALREADY_SET"; @Override public void onReceive(Context context, Intent intent) { String receStr = intent.getStringExtra("MESSAGE"); if (intent.getAction().equals(ACTION_SYSTEM_TIM_ALREADY_SET)){ //do something } }}
以上就是整个过程,代码比较简单,但是要从开始一直到完善还是花了很多时间,相当于复习了应用编写到系统应用在源码环境下编译的整个过程了。
- 应用获取时间戳异常后通过系统应用修改时间
- 应用-修改系统时间
- Android通过应用来设置系统时间
- 通过Android应用更改系统时间
- Android其他应用修改系统时间
- 安卓应用修改系统时间
- php通过gmtime()获取的时间戳,格式化后与系统时间不一致
- 通过php修改系统时间
- 通过api欺骗获取安卓应用的启动时间
- Android 通过应用设置系统日期和时间的方法
- Android 通过应用设置系统日期和时间的方法
- Android 通过应用设置系统日期和时间的方法
- Android 通过应用设置系统日期和时间的方法
- date 获取、修改系统时间
- A启动系统设置应用的时间设置Activity去修改时间,修改后返回到A,A挂掉了
- 从应用层修改系统日期和时间
- C语言实战应用第一课:获取系统当前时间
- 获取系统权限修改系统时间
- HTML 根据条件查询
- 装饰模式
- MFC Base64和MD5的加密算法
- Jihosoft File Recovery(文件数据恢复软件)官方破解版V8.2.7下载 | file recovery 破解版
- [距离限制模型 & 网络流] BZOJ3144 :[Hnoi2013] 切糕
- 应用获取时间戳异常后通过系统应用修改时间
- 阿里云---阿里云服务器ECS安装jdk环境
- Nginx expires缓存
- centos 6.5 忘记root密码的解决办法
- 算法时间复杂度与空间复杂度
- Git基本常用命令
- [LeetCode]对称二叉树
- Comutil类
- CocosCreator-Label