http://www.oschina.net/question/54100_31740
感谢博主的第一种方法,第二种方法没有尝试,
工作流程如下记录:
1. 有wifi的情况下获取ntp时间
2. 用获取NTP时间Android已经有现成的类D:\work_java\Android\sdk-meng\sources\android-19\android\net\SntpClient.java, 但是 是隐形的类.
源码中可见{@hide} 表示隐形类不能直接调用.所以要想其他的办法调用
3. 隐形的api在window的编译环境下不能直接调用包括以下几个办法:
- 直接复制SntpClient.java整个类到自己的工程下
- 源码编译工程
- java反射调用
4. 本次用java反射方法调用SntpClient类, 新编写类SntpTime
5. 在适当地方调用此类 之后执行SystemClock.setCurrentTimeMillis(sntpTime);
6. 修改AndroidManifest.xml 在manifest添加 android:sharedUserId="android.uid.system"
在win编译不通过提示错误
"http://schemas.android.com/apk/res/android"
package="com.csctek.android.iserver.services"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="android.uid.system">
SystemClock.setCurrentTimeMillis(sntpTime);
无论怎么调用这个函数都是没用的,无论模拟器还是真机,在logcat中总会得到”Unable to open alarm driver: Permission denied “package com.android.myapp.sntptime;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import java.lang.reflect.Method;
import java.util.Date;
/** * Created by user on 2016/11/28. */
public class SntpTime {
private String TAG = "SntpTime";
private String mIp;
private int mTimeOut;
private Handler mOtherHandler;
private int mHandlerWhatNumber;
// 时间获取ip地址 // socket超时时间 // 消息句柄// 消息标号自定义What数字
public SntpTime (String ip, int timeOut, Handler handler, int handlerWhatNumber) {
this.mIp = ip;
this.mTimeOut = timeOut;
this.mOtherHandler = handler;
this.mHandlerWhatNumber = handlerWhatNumber;
Log.i(TAG, "SntpTime: " + mIp + " " + mTimeOut + " " + mHandlerWhatNumber);
}
public void getTime() {
new Thread() {
public void run() {
//使用隐形类
try {
Class C;
//通过名字查找类 class
C = Class.forName("android.net.SntpClient");
Log.i(TAG, "class is " + C);
Object obj = C.newInstance();
try {
//函数参数 2个 requestTime
//根据名字和参数个数查找函数
Method m = C.getMethod("requestTime", new Class[]{String.class, int.class});
//参数值以数组的形式传入,格式与Class一样
//调用函数
Object o = m.invoke(obj, new Object[]{mIp, mTimeOut});
//返回值转换
boolean b = (Boolean)o;
Log.i(TAG, "return is " + b);
if (b) {
//SntpClient.getNtpTime() //return time value computed from NTP server response
Method mGetNtpTime = C.getMethod("getNtpTime", new Class[]{});
Object oGetNtpTime = mGetNtpTime.invoke(obj, new Object[]{});
Long ntpTime = (Long)oGetNtpTime;
Log.i(TAG, "ntpTime is " + ntpTime);
//SntpClient.getNtpTimeReference() == SystemClock.elapsedRealtime()
//reference clock corresponding to the NTP time
Method mGetNtpTimeReference = C.getMethod("getNtpTimeReference", new Class[]{});
Object oGetNtpTimeReference = mGetNtpTimeReference.invoke(obj, new Object[]{});
Long ntpTimeReference = (Long)oGetNtpTimeReference;
Log.i(TAG, "ntpTimeReference is " + ntpTimeReference);
////////////////////////////////
Log.i(TAG, "SystemClock.elapsedRealtime() is "+ SystemClock.elapsedRealtime());
Log.i(TAG, "System.currentTimeMillis() is "+ System.currentTimeMillis());
Date test0 = new Date(ntpTime);
Log.i(TAG, "ntpTime is Date.toString()" + test0.toString());
Date test1 = new Date(System.currentTimeMillis());
Log.i(TAG, "System.currentTimeMillis() is Date.toString()" + test1.toString());
//很多网上的公式我这里测试返回的结果是错误的如: long now = client.getNtpTime() + System.nanoTime() / 1000 - client.getNtpTimeReference();
//本人这个计算公式是源码SntpClient.java源码注释中提供的,可自己查看
long nowTime = ntpTime + SystemClock.elapsedRealtime() - ntpTimeReference;
updateTimeAndDate(nowTime);
Date currentTime = new Date(nowTime);
Message toOtherHandler = new Message();
toOtherHandler.what = mHandlerWhatNumber;
toOtherHandler.obj = nowTime;
Log.i(TAG, "mHandlerWhatNumber is "+ mHandlerWhatNumber + "time : " + currentTime.toString());
mOtherHandler.sendMessage(toOtherHandler);
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "GetClass SntpClient is error! two ");
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "GetClass SntpClient is error! one ");
}
}
}.start();
}
private void updateTimeAndDate(Long sntpTime) {
long systemTime = System.currentTimeMillis();
Log.i(ISSERVICE, "Time////System.currentTimeMillis() is " + System.currentTimeMillis());
Log.i(ISSERVICE, "Time////sntpTime is " + sntpTime);
Log.i(ISSERVICE, "Time////(systemTime - sntpTime) = " + (systemTime - sntpTime));
//if((systemTime - sntpTime >= 1000*60 ) || (systemTime - sntpTime <= -1000*60) ) {
//时间格式修改
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd.HHmmss");//yyyy-MM-dd HH:mm:ss
String format = df.format(new Date(sntpTime));
Log.i(TAG, "Time////format is " + format);
boolean b = SystemClock.setCurrentTimeMillis(sntpTime);
Log.i(TAG, "Time////System.currentTimeMillis() is " + System.currentTimeMillis() + "return currentTimeMillis bool = " + b);
// }
}
}
SntpTime类中有构造函数传入一个Handler, 所以我们通过Handler得到msg也就是NTP上的时间, 传递给主调函数,给系统设置时间
private void startSntpTime() {
//参数1 表示Ip
//参数2 超时时间
//参数3 Handler
//参数4 传入的Handler.What值
SntpTime currentTime = new SntpTime(ISGlobleBaseData.SNTP_TIME_IP, 30000, mHandler, ISServiceHandleMessage.SNTP_TIME_HANDLER);
currentTime.getTime();
}
/////////////////////////////////Handler消息分类
//Long这里一定要用 Long 代替long 否则linux源码mm编译的时候会报错
case ISServiceHandleMessage.SNTP_TIME_HANDLER:
Long time = (Long)msg.obj;
Log.i(ISSERVICE, "time//// = " + String.valueOf(time));
break;
///////////////////////////////////////////////