在安卓中同步服务器时间有多种方法,我来为你详细介绍几种常见的方案:
1. 使用 HTTP 请求获取服务器时间
public class TimeSyncUtils { public static long getServerTime(String url) { try { URL serverUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) serverUrl.openConnection(); connection.setRequestMethod("HEAD"); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); long serverTime = connection.getDate(); connection.disconnect(); return serverTime; } catch (Exception e) { e.printStackTrace(); return -1; } } // 使用示例 public static void syncTime() { long serverTime = getServerTime("https://your-server.com/api"); if (serverTime > 0) { long deviceTime = System.currentTimeMillis(); long timeDiff = serverTime - deviceTime; // 保存时间差,在应用中使用 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs.edit().putLong("time_offset", timeDiff).apply(); } } // 获取校准后的时间 public static long getAdjustedTime() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); long offset = prefs.getLong("time_offset", 0); return System.currentTimeMillis() + offset; } }
2. 使用 NTP 协议同步时间(推荐)
添加依赖:
implementation 'commons-net:commons-net:3.8.0'
import org.apache.commons.net.ntp.NTPUDPClient; import org.apache.commons.net.ntp.TimeInfo; public class NTPTimeSync { public static long getNTPTime() { NTPUDPClient client = new NTPUDPClient(); client.setDefaultTimeout(10000); try { client.open(); InetAddress hostAddr = InetAddress.getByName("pool.ntp.org"); TimeInfo info = client.getTime(hostAddr); info.computeDetails(); Long offset = info.getOffset(); Long delay = info.getDelay(); if (offset != null) { return System.currentTimeMillis() + offset; } } catch (Exception e) { e.printStackTrace(); } finally { client.close(); } return -1; } }
3. 使用 SNTP 客户端
import android.os.SystemClock; public class SntpClient { private static final int ORIGINATE_TIME_OFFSET = 24; private static final int RECEIVE_TIME_OFFSET = 32; private static final int TRANSMIT_TIME_OFFSET = 40; private static final int NTP_PACKET_SIZE = 48; private static final int NTP_PORT = 123; private static final int NTP_MODE_CLIENT = 3; private static final int NTP_VERSION = 3; public boolean requestTime(String host, int timeout) { try { DatagramSocket socket = new DatagramSocket(); socket.setSoTimeout(timeout); InetAddress address = InetAddress.getByName(host); byte[] buffer = new byte[NTP_PACKET_SIZE]; DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT); buffer[0] = (NTP_MODE_CLIENT | (NTP_VERSION << 3)); long requestTime = System.currentTimeMillis(); long requestTicks = SystemClock.elapsedRealtime(); writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime); socket.send(request); DatagramPacket response = new DatagramPacket(buffer, buffer.length); socket.receive(response); long responseTicks = SystemClock.elapsedRealtime(); long responseTime = requestTime + (responseTicks - requestTicks); long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET); long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET); long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET); long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime); long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2; // 保存时间偏移量 saveTimeOffset(clockOffset); socket.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } private long readTimeStamp(byte[] buffer, int offset) { long seconds = read32(buffer, offset); long fraction = read32(buffer, offset + 4); return ((seconds - 2208988800L) * 1000) + ((fraction * 1000L) / 0x100000000L); } private void writeTimeStamp(byte[] buffer, int offset, long time) { long seconds = time / 1000L + 2208988800L; long fraction = ((time % 1000L) * 0x100000000L) / 1000L; write32(buffer, offset, (int) seconds); write32(buffer, offset + 4, (int) fraction); } private long read32(byte[] buffer, int offset) { byte b0 = buffer[offset]; byte b1 = buffer[offset + 1]; byte b2 = buffer[offset + 2]; byte b3 = buffer[offset + 3]; return ((b0 & 0xFF) << 24) | ((b1 & 0xFF) << 16) | ((b2 & 0xFF) << 8) | (b3 & 0xFF); } private void write32(byte[] buffer, int offset, int value) { buffer[offset] = (byte) ((value >> 24) & 0xff); buffer[offset + 1] = (byte) ((value >> 16) & 0xff); buffer[offset + 2] = (byte) ((value >> 8) & 0xff); buffer[offset + 3] = (byte) (value & 0xff); } private void saveTimeOffset(long offset) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs.edit().putLong("ntp_time_offset", offset).apply(); } }
4. 定期同步的 Service
public class TimeSyncService extends Service { private static final long SYNC_INTERVAL = 30 * 60 * 1000; // 30分钟 private Handler handler = new Handler(); private Runnable syncRunnable = new Runnable() { @Override public void run() { syncTimeWithServer(); handler.postDelayed(this, SYNC_INTERVAL); } }; @Override public int onStartCommand(Intent intent, int flags, int startId) { handler.post(syncRunnable); return START_STICKY; } private void syncTimeWithServer() { // 使用上述任意方法同步时间 long serverTime = NTPTimeSync.getNTPTime(); if (serverTime > 0) { // 保存时间偏移或直接使用 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs.edit().putLong("last_sync_time", System.currentTimeMillis()) .putLong("time_offset", serverTime - System.currentTimeMillis()) .apply(); } } @Override public IBinder onBind(Intent intent) { return null; } }
5. 常用 NTP 服务器地址
public class NtpServers { public static final String[] SERVERS = { "pool.ntp.org", "time.google.com", "time.apple.com", "time.windows.com", "cn.pool.ntp.org", // 中国地区 "ntp.aliyun.com" // 阿里云 }; }
注意事项:
1、权限要求:需要网络权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2、时间校准:普通应用无法修改系统时间,只能记录偏移量在应用内使用
3、网络延迟:需要考虑网络延迟对时间同步精度的影响
4、定期同步:建议定期同步以保持时间准确性
选择哪种方法取决于你的具体需求:如果只需要相对时间,HTTP 方法足够;如果需要高精度时间,推荐使用 NTP 协议。
文章摘自:https://idc.huochengrm.cn/fwq/16753.html
评论