Repository: itsMelo/AndroidSocket Branch: master Commit: 525513e25e8c Files: 50 Total size: 73.8 KB Directory structure: gitextract_wfs9muuq/ ├── .gitignore ├── AppSocket/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── melo/ │ │ └── com/ │ │ └── androidsocket/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── melo/ │ │ │ └── com/ │ │ │ └── androidsocket/ │ │ │ ├── bean/ │ │ │ │ └── Users.java │ │ │ ├── common/ │ │ │ │ └── Config.java │ │ │ ├── listener/ │ │ │ │ ├── OnConnectionStateListener.java │ │ │ │ └── OnMessageReceiveListener.java │ │ │ ├── socket/ │ │ │ │ ├── SocketManager.java │ │ │ │ ├── tcp/ │ │ │ │ │ └── TCPSocket.java │ │ │ │ └── udp/ │ │ │ │ └── UDPSocket.java │ │ │ └── utils/ │ │ │ ├── DeviceUtil.java │ │ │ ├── HeartbeatTimer.java │ │ │ └── WifiUtil.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── melo/ │ └── com/ │ └── androidsocket/ │ └── ExampleUnitTest.java ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── melo/ │ │ └── com/ │ │ └── app/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── melo/ │ │ │ └── com/ │ │ │ └── app/ │ │ │ └── MainActivity.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ └── content_main.xml │ │ ├── menu/ │ │ │ └── menu_main.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── melo/ │ └── com/ │ └── app/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures .externalNativeBuild ================================================ FILE: AppSocket/.gitignore ================================================ /build ================================================ FILE: AppSocket/build.gradle ================================================ apply plugin: 'com.android.library' apply plugin: 'com.jakewharton.butterknife' android { compileSdkVersion 26 defaultConfig { minSdkVersion 21 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' compile 'com.jakewharton:butterknife:8.5.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' } ================================================ FILE: AppSocket/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: AppSocket/src/androidTest/java/melo/com/androidsocket/ExampleInstrumentedTest.java ================================================ package melo.com.androidsocket; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumented test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("melo.com.androidsocket", appContext.getPackageName()); } } ================================================ FILE: AppSocket/src/main/AndroidManifest.xml ================================================ ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/bean/Users.java ================================================ package melo.com.androidsocket.bean; public class Users { private int softVersion; private int romVersion; private String imei; private String device; private String ip; private String loginTime; public int getSoftVersion() { return softVersion; } public void setSoftVersion(int softVersion) { this.softVersion = softVersion; } public int getRomVersion() { return romVersion; } public void setRomVersion(int romVersion) { this.romVersion = romVersion; } public String getImei() { return imei; } public void setImei(String imei) { this.imei = imei; } public String getDevice() { return device; } public void setDevice(String device) { this.device = device; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getLoginTime() { return loginTime; } public void setLoginTime(String loginTime) { this.loginTime = loginTime; } } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/common/Config.java ================================================ package melo.com.androidsocket.common; /** * Created by melo on 2017/11/27. */ public class Config { public static final String MSG = "msg"; public static final String HEARTBREAK = "heartbreak"; public static final String PING = "ping"; public static final String TCP_IP = "ip"; public static final String TCP_PORT = "port"; // 单个CPU线程池大小 public static final int POOL_SIZE = 5; /** * 错误处理 */ public static class ErrorCode { public static final int CREATE_TCP_ERROR = 1; public static final int PING_TCP_TIMEOUT = 2; } } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/listener/OnConnectionStateListener.java ================================================ package melo.com.androidsocket.listener; /** * Created by melo on 2017/11/29. */ public interface OnConnectionStateListener { void onSuccess(); void onFailed(int errorCode); } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/listener/OnMessageReceiveListener.java ================================================ package melo.com.androidsocket.listener; /** * Created by melo on 2017/11/27. */ public interface OnMessageReceiveListener { void onMessageReceived(String message); } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/socket/SocketManager.java ================================================ package melo.com.androidsocket.socket; import android.content.Context; import android.text.TextUtils; import org.json.JSONException; import org.json.JSONObject; import melo.com.androidsocket.common.Config; import melo.com.androidsocket.listener.OnConnectionStateListener; import melo.com.androidsocket.listener.OnMessageReceiveListener; import melo.com.androidsocket.socket.tcp.TCPSocket; import melo.com.androidsocket.socket.udp.UDPSocket; /** * Created by melo on 2017/11/27. */ public class SocketManager { private static volatile SocketManager instance = null; private UDPSocket udpSocket; private TCPSocket tcpSocket; private Context mContext; private SocketManager(Context context) { mContext = context.getApplicationContext(); } public static SocketManager getInstance(Context context) { // if already inited, no need to get lock everytime if (instance == null) { synchronized (SocketManager.class) { if (instance == null) { instance = new SocketManager(context); } } } return instance; } public void startUdpConnection() { if (udpSocket == null) { udpSocket = new UDPSocket(mContext); } // 注册接收消息的接口 udpSocket.addOnMessageReceiveListener(new OnMessageReceiveListener() { @Override public void onMessageReceived(String message) { handleUdpMessage(message); } }); udpSocket.startUDPSocket(); } /** * 处理 udp 收到的消息 * * @param message */ private void handleUdpMessage(String message) { try { JSONObject jsonObject = new JSONObject(message); String ip = jsonObject.optString(Config.TCP_IP); String port = jsonObject.optString(Config.TCP_PORT); if (!TextUtils.isEmpty(ip) && !TextUtils.isEmpty(port)) { startTcpConnection(ip, port); } } catch (JSONException e) { e.printStackTrace(); } } /** * 开始 TCP 连接 * * @param ip * @param port */ private void startTcpConnection(String ip, String port) { if (tcpSocket == null) {// 保证收到消息后,只创建一次 tcpSocket = new TCPSocket(mContext); tcpSocket.startTcpSocket(ip, port); tcpSocket.setOnConnectionStateListener(new OnConnectionStateListener() { @Override public void onSuccess() {// tcp 创建成功 udpSocket.stopHeartbeatTimer(); } @Override public void onFailed(int errorCode) {// tcp 异常处理 switch (errorCode) { case Config.ErrorCode.CREATE_TCP_ERROR: break; case Config.ErrorCode.PING_TCP_TIMEOUT: udpSocket.startHeartbeatTimer(); tcpSocket = null; break; } } }); } } public void stopSocket() { udpSocket.stopUDPSocket(); tcpSocket.stopTcpConnection(); if (udpSocket != null) { udpSocket = null; } if (tcpSocket != null) { tcpSocket = null; } } } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/socket/tcp/TCPSocket.java ================================================ package melo.com.androidsocket.socket.tcp; import android.content.Context; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import melo.com.androidsocket.common.Config; import melo.com.androidsocket.listener.OnConnectionStateListener; import melo.com.androidsocket.utils.HeartbeatTimer; /** * Created by melo on 2017/11/28. */ public class TCPSocket { private static final String TAG = "TCPSocket"; private Context mContext; private ExecutorService mThreadPool; private Socket mSocket; private BufferedReader br; private PrintWriter pw; private HeartbeatTimer timer; private long lastReceiveTime = 0; private OnConnectionStateListener mListener; private static final long TIME_OUT = 15 * 1000; private static final long HEARTBEAT_MESSAGE_DURATION = 2 * 1000; public TCPSocket(Context context) { this.mContext = context; int cpuNumbers = Runtime.getRuntime().availableProcessors(); // 根据CPU数目初始化线程池 mThreadPool = Executors.newFixedThreadPool(cpuNumbers * Config.POOL_SIZE); // 记录创建对象时的时间 lastReceiveTime = System.currentTimeMillis(); } public void startTcpSocket(final String ip, final String port) { mThreadPool.execute(new Runnable() { @Override public void run() { if (startTcpConnection(ip, Integer.valueOf(port))) {// 尝试建立 TCP 连接 if (mListener != null) { mListener.onSuccess(); } startReceiveTcpThread(); startHeartbeatTimer(); } else { if (mListener != null) { mListener.onFailed(Config.ErrorCode.CREATE_TCP_ERROR); } } } }); } public void setOnConnectionStateListener(OnConnectionStateListener listener) { this.mListener = listener; } /** * 创建接收线程 */ private void startReceiveTcpThread() { mThreadPool.execute(new Runnable() { @Override public void run() { String line = ""; try { while ((line = br.readLine()) != null) { handleReceiveTcpMessage(line); } } catch (IOException e) { e.printStackTrace(); } } }); } /** * 处理 tcp 收到的消息 * * @param line */ private void handleReceiveTcpMessage(String line) { Log.d(TAG, "接收 tcp 消息:" + line); lastReceiveTime = System.currentTimeMillis(); } private void sendTcpMessage(String json) { pw.println(json); Log.d(TAG, "tcp 消息发送成功..."); } /** * 启动心跳 */ private void startHeartbeatTimer() { if (timer == null) { timer = new HeartbeatTimer(); } timer.setOnScheduleListener(new HeartbeatTimer.OnScheduleListener() { @Override public void onSchedule() { Log.d(TAG, "timer is onSchedule..."); long duration = System.currentTimeMillis() - lastReceiveTime; Log.d(TAG, "duration:" + duration); if (duration > TIME_OUT) {//若超过十五秒都没收到我的心跳包,则认为对方不在线。 Log.d(TAG, "tcp ping 超时,对方已经下线"); stopTcpConnection(); if (mListener != null) { mListener.onFailed(Config.ErrorCode.PING_TCP_TIMEOUT); } } else if (duration > HEARTBEAT_MESSAGE_DURATION) {//若超过两秒他没收到我的心跳包,则重新发一个。 JSONObject jsonObject = new JSONObject(); try { jsonObject.put(Config.MSG, Config.PING); } catch (JSONException e) { e.printStackTrace(); } sendTcpMessage(jsonObject.toString()); } } }); timer.startTimer(0, 1000 * 2); } public void stopHeartbeatTimer() { if (timer != null) { timer.exit(); timer = null; } } /** * 尝试建立tcp连接 * * @param ip * @param port */ private boolean startTcpConnection(final String ip, final int port) { try { if (mSocket == null) { mSocket = new Socket(ip, port); mSocket.setKeepAlive(true); mSocket.setTcpNoDelay(true); mSocket.setReuseAddress(true); } InputStream is = mSocket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); OutputStream os = mSocket.getOutputStream(); pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os)), true); Log.d(TAG, "tcp 创建成功..."); return true; } catch (Exception e) { e.printStackTrace(); } return false; } public void stopTcpConnection() { try { stopHeartbeatTimer(); if (br != null) { br.close(); } if (pw != null) { pw.close(); } if (mThreadPool != null) { mThreadPool.shutdown(); mThreadPool = null; } if (mSocket != null) { mSocket.close(); mSocket = null; } } catch (IOException e) { e.printStackTrace(); } } } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/socket/udp/UDPSocket.java ================================================ package melo.com.androidsocket.socket.udp; import android.content.Context; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import melo.com.androidsocket.bean.Users; import melo.com.androidsocket.common.Config; import melo.com.androidsocket.listener.OnMessageReceiveListener; import melo.com.androidsocket.utils.DeviceUtil; import melo.com.androidsocket.utils.HeartbeatTimer; import melo.com.androidsocket.utils.WifiUtil; /** * Created by melo on 2017/9/20. */ public class UDPSocket { private static final String TAG = "UDPSocket"; private static final int BUFFER_LENGTH = 1024; private byte[] receiveByte = new byte[BUFFER_LENGTH]; private static String BROADCAST_IP = "192.168.43.255"; // 端口号,飞鸽协议默认端口2425 public static final int CLIENT_PORT = 2425; private boolean isThreadRunning = false; private Context mContext; private DatagramSocket client; private DatagramPacket receivePacket; private long lastReceiveTime = 0; private static final long TIME_OUT = 120 * 1000; private static final long HEARTBEAT_MESSAGE_DURATION = 5 * 1000; private ExecutorService mThreadPool; private Thread clientThread; private HeartbeatTimer timer; private Users localUser; private Users remoteUser; private final List messageReceiveList; public UDPSocket(Context context) { this.mContext = context; int cpuNumbers = Runtime.getRuntime().availableProcessors(); // 根据CPU数目初始化线程池 mThreadPool = Executors.newFixedThreadPool(cpuNumbers * Config.POOL_SIZE); // 记录创建对象时的时间 lastReceiveTime = System.currentTimeMillis(); messageReceiveList = new ArrayList<>(); Log.d(TAG, "创建 UDP 对象"); // createUser(); } public void addOnMessageReceiveListener(OnMessageReceiveListener listener) { messageReceiveList.add(listener); } /** * 创建本地用户信息 */ private void createUser() { if (localUser == null) { localUser = new Users(); } if (remoteUser == null) { remoteUser = new Users(); } localUser.setImei(DeviceUtil.getDeviceId(mContext)); localUser.setSoftVersion(DeviceUtil.getPackageVersionCode(mContext)); if (WifiUtil.getInstance(mContext).isWifiApEnabled()) {// 判断当前是否是开启热点方 localUser.setIp("192.168.43.1"); } else {// 当前是开启 wifi 方 localUser.setIp(WifiUtil.getInstance(mContext).getLocalIPAddress()); remoteUser.setIp(WifiUtil.getInstance(mContext).getServerIPAddress()); } } public void startUDPSocket() { if (client != null) return; try { // 表明这个 Socket 在设置的端口上监听数据。 client = new DatagramSocket(CLIENT_PORT); client.setReuseAddress(true); if (receivePacket == null) { // 创建接受数据的 packet receivePacket = new DatagramPacket(receiveByte, BUFFER_LENGTH); } startSocketThread(); } catch (SocketException e) { e.printStackTrace(); } } /** * 开启接收数据的线程 */ private void startSocketThread() { clientThread = new Thread(new Runnable() { @Override public void run() { receiveMessage(); } }); isThreadRunning = true; clientThread.start(); Log.d(TAG, "开启 UDP 数据接收线程"); startHeartbeatTimer(); } /** * 处理接受到的消息 */ private void receiveMessage() { while (isThreadRunning) { try { if (client != null) { client.receive(receivePacket); } lastReceiveTime = System.currentTimeMillis(); Log.d(TAG, "receive packet success..."); } catch (IOException e) { Log.e(TAG, "UDP数据包接收失败!线程停止"); stopUDPSocket(); e.printStackTrace(); return; } if (receivePacket == null || receivePacket.getLength() == 0) { Log.e(TAG, "无法接收UDP数据或者接收到的UDP数据为空"); continue; } String strReceive = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength()); Log.d(TAG, strReceive + " from " + receivePacket.getAddress().getHostAddress() + ":" + receivePacket.getPort()); //解析接收到的 json 信息 notifyMessageReceive(strReceive); // 每次接收完UDP数据后,重置长度。否则可能会导致下次收到数据包被截断。 if (receivePacket != null) { receivePacket.setLength(BUFFER_LENGTH); } } } /** * 将消息通过接口发送到每个页面 * * @param strReceive */ private void notifyMessageReceive(String strReceive) { for (OnMessageReceiveListener listener : messageReceiveList) { if (listener != null) { listener.onMessageReceived(strReceive); } } } public void stopUDPSocket() { isThreadRunning = false; receivePacket = null; stopHeartbeatTimer(); if (clientThread != null) { clientThread.interrupt(); } if (mThreadPool != null) { mThreadPool.shutdown(); } if (client != null) { client.close(); client = null; } if (timer != null) { timer.exit(); } } /** * 启动心跳,timer 间隔十秒 */ public void startHeartbeatTimer() { if (timer == null) { timer = new HeartbeatTimer(); } timer.setOnScheduleListener(new HeartbeatTimer.OnScheduleListener() { @Override public void onSchedule() { Log.d(TAG, "timer is onSchedule..."); long duration = System.currentTimeMillis() - lastReceiveTime; Log.d(TAG, "duration:" + duration); if (duration > TIME_OUT) {//若超过两分钟都没收到我的心跳包,则认为对方不在线。 Log.d(TAG, "超时,对方已经下线"); // 刷新时间,重新进入下一个心跳周期 lastReceiveTime = System.currentTimeMillis(); } else if (duration > HEARTBEAT_MESSAGE_DURATION) {//若超过十秒他没收到我的心跳包,则重新发一个。 JSONObject jsonObject = new JSONObject(); try { jsonObject.put(Config.MSG, Config.HEARTBREAK); } catch (JSONException e) { e.printStackTrace(); } sendMessage(jsonObject.toString()); } } }); timer.startTimer(0, 1000 * 5); } public void stopHeartbeatTimer() { if (timer != null) { timer.exit(); timer = null; } } /** * 发送心跳包 * * @param message */ public void sendMessage(final String message) { mThreadPool.execute(new Runnable() { @Override public void run() { try { BROADCAST_IP = WifiUtil.getBroadcastAddress(); Log.d(TAG, "BROADCAST_IP:" + BROADCAST_IP); InetAddress targetAddress = InetAddress.getByName(BROADCAST_IP); DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), targetAddress, CLIENT_PORT); client.send(packet); // 数据发送事件 Log.d(TAG, "数据发送成功"); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); } } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/utils/DeviceUtil.java ================================================ package melo.com.androidsocket.utils; import android.app.Service; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.PowerManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.DisplayMetrics; import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.NetworkInterface; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; /** * 获取设备的信息 * * @author melo */ public final class DeviceUtil { /** *

IMEI.

Returns the unique device ID, for example, the IMEI for GSM and the MEID * or ESN for CDMA phones. Return null if device ID is not available. *

* Requires Permission: READ_PHONE_STATE * * @param context * @return */ public synchronized static String getDeviceId(Context context) { if (context == null) { return ""; } String imei = ""; try { TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (tm == null || TextUtils.isEmpty(tm.getDeviceId())) { // 双卡双待需要通过phone1和phone2获取imei,默认取phone1的imei。 tm = (TelephonyManager) context.getSystemService("phone1"); } if (tm != null) { imei = tm.getDeviceId(); } } catch (SecurityException e) { e.printStackTrace(); } return imei; } /** * Returns the serial number of the SIM, if applicable. Return null if it is * unavailable. *

* Requires Permission: READ_PHONE_STATE * * @param context * @return */ public synchronized static String getSimSerialNumber(Context context) { if (context == null) { return ""; } final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); return tm.getSimSerialNumber(); } /** * A 64-bit number (as a hex string) that is randomly generated on the * device's first boot and should remain constant for the lifetime of the * device. (The value may change if a factory reset is performed on the * device.) * * @param context * @return */ public synchronized static String getAndroidID(Context context) { return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); } /** * 操作系统版本 * * @return */ public static String getOSversion() { return android.os.Build.VERSION.RELEASE; } /** * 设备商 * * @return */ public static String getManufacturer() { return android.os.Build.MANUFACTURER; } /** * 设备型号 * * @return */ public static String getModel() { return android.os.Build.MODEL; } /** * 序列号 * * @return */ public static String getSerialNumber() { String serial = null; try { Class c = Class.forName("android.os.SystemProperties"); Method get = c.getMethod("get", String.class); serial = (String) get.invoke(c, "ro.serialno"); } catch (Exception ignored) { } return serial; } /** * SD CARD ID * * @return */ public static synchronized String getSDcardID() { try { String sdCid = null; String[] memBlkArray = new String[]{"/sys/block/mmcblk0", "/sys/block/mmcblk1", "/sys/block/mmcblk2"}; for (String memBlk : memBlkArray) { File file = new File(memBlk); if (file.exists() && file.isDirectory()) { Process cmd = Runtime.getRuntime().exec("cat " + memBlk + "/device/cid"); BufferedReader br = new BufferedReader(new InputStreamReader(cmd.getInputStream())); sdCid = br.readLine(); if (!TextUtils.isEmpty(sdCid)) { return sdCid; } } } return null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } /** * 获取mac地址 * * @param context * @return */ public static String getMac(Context context) { if (context == null) { return ""; } String mac = null; try { final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); if (wifi != null) { WifiInfo info = wifi.getConnectionInfo(); if (null != info && info.getMacAddress() != null) { mac = info.getMacAddress(); } } } catch (Exception e) { e.printStackTrace(); } return mac; } /** * 获取mac地址 * 可以突破android6.0的限制 * * @return */ public static String getWifiMacAddress() { try { String interfaceName = "wlan0"; List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); for (NetworkInterface intf : interfaces) { if (!intf.getName().equalsIgnoreCase(interfaceName)) { continue; } byte[] mac = intf.getHardwareAddress(); if (mac == null) { return ""; } StringBuilder buf = new StringBuilder(); for (byte aMac : mac) { buf.append(String.format("%02X:", aMac)); } if (buf.length() > 0) { buf.deleteCharAt(buf.length() - 1); } return buf.toString(); } } catch (Exception ex) { } // for now eat exceptions return ""; } /** * 获取IMSI * * @param context * @return */ public static String getIMSI(Context context) { TelephonyManager tm = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); return tm.getSubscriberId(); } /** * get sim serial number */ public static String getSimSerialNum(Context context) { TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE); return tm.getSimSerialNumber(); } /** * 获取屏幕的分辨率 * * @param context * @return int array with 2 items. The first item is width, and the second is height. */ public static int[] getScreenResolution(Context context) { DisplayMetrics dm = context.getResources().getDisplayMetrics(); int[] resolution = new int[2]; resolution[0] = dm.widthPixels; resolution[1] = dm.heightPixels; return resolution; } /** * 获取WIFI的Mac地址 * * @param context * @return Wifi的BSSID即mac地址 */ public static String getWifiBSSID(Context context) { if (context == null) { return null; } String mac = null; WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo info = wm.getConnectionInfo(); if (info != null) { mac = info.getBSSID();// 获得本机的MAC地址 } return mac; } public static String getPackageVersion(Context context) { PackageManager packageManager = context.getPackageManager(); PackageInfo packInfo; try { packInfo = packageManager.getPackageInfo(context.getPackageName(), 0); return packInfo.versionName; } catch (NameNotFoundException e) { e.printStackTrace(); } return null; } public static int getPackageVersionCode(Context context) { PackageManager packageManager = context.getPackageManager(); PackageInfo packInfo; try { packInfo = packageManager.getPackageInfo(context.getPackageName(), 0); return packInfo.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } return 0; } /** * 获取系统休眠时间。 * * @return */ public static int getScreenOffTimeOut(Context context) { int sleepTime; try { sleepTime = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT); } catch (SettingNotFoundException e) { e.printStackTrace(); sleepTime = 15 * 1000; } return sleepTime; } public static boolean isScreenOn(Context context) { PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); return powerManager.isScreenOn(); } /** * Gets the number of cores available in this device, across all processors. * Requires: Ability to peruse the filesystem at "/sys/devices/system/cpu" * * @return The number of cores, or 1 if failed to get result */ public static int getCPUNumCores() { try { //Get directory containing CPU info File dir = new File("/sys/devices/system/cpu/"); //Filter to only list the devices we care about File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { //Check if filename is "cpu", followed by a single digit number if (Pattern.matches("cpu[0-9]", pathname.getName())) { return true; } return false; } }); //Return the number of cores (virtual CPU devices) return files.length; } catch (Exception e) { return 1; } } /** * 获取系统参数 * * @param configName * @return */ public static String getSystemConf(String configName) { try { Process process = Runtime.getRuntime().exec("getprop " + configName); InputStreamReader ir = new InputStreamReader(process.getInputStream()); BufferedReader input = new BufferedReader(ir); String value = input.readLine(); input.close(); ir.close(); process.destroy(); return value; } catch (Exception e) { e.printStackTrace(); } return ""; } /** * 获取硬件版本 * * @return */ public static String getHardwareVersion() { return getSystemConf("ro.hardware"); } /** * 获取rom版本 */ public static String getRomVersion() { return getSystemConf("ro.mediatek.version.release"); } /** * 获取hq rom版本 */ private static String gethqRomVersion() { return getSystemConf("ro.huaqin.version.release"); } public static String getShowhqRomVersion() { String showHq = "hq"; String hqRomVer = gethqRomVersion(); if (TextUtils.isEmpty(hqRomVer) == false) { String[] s = hqRomVer.split("_"); if (s != null && s.length >= 3) { showHq = s[2]; } } return showHq; } /** * 获取installed apk版本 */ public static PackageInfo getInstalledAppInfo(Context context, String pname) { try { List packages = context.getPackageManager().getInstalledPackages(0); if (packages != null) { for (PackageInfo pinfo : packages) { if (pinfo != null && pinfo.packageName.equals(pname)) { return pinfo; } } } } catch (Exception e) { e.printStackTrace(); } return null; } } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/utils/HeartbeatTimer.java ================================================ package melo.com.androidsocket.utils; import java.util.Timer; import java.util.TimerTask; /** * Created by melo on 2017/9/21. */ public class HeartbeatTimer { private Timer timer; private TimerTask task; private OnScheduleListener mListener; public HeartbeatTimer() { timer = new Timer(); } public void startTimer(long delay, long period) { task = new TimerTask() { @Override public void run() { if (mListener != null) { mListener.onSchedule(); } } }; timer.schedule(task, delay, period); } public void exit() { if (task != null) { task.cancel(); } if (timer != null) { timer.cancel(); } } public interface OnScheduleListener { void onSchedule(); } public void setOnScheduleListener(OnScheduleListener listener) { this.mListener = listener; } } ================================================ FILE: AppSocket/src/main/java/melo/com/androidsocket/utils/WifiUtil.java ================================================ package melo.com.androidsocket.utils; import android.content.Context; import android.net.DhcpInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.util.Enumeration; import java.util.Iterator; import java.util.List; /** * Created by melo on 2017/9/23. */ public class WifiUtil { private static final String TAG = "LocationUtils"; private static volatile WifiUtil instance = null; private WifiManager mWifiManager; private Context mContext; private WifiUtil(Context context) { mContext = context; mWifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE); } public static WifiUtil getInstance(Context context) { if (instance == null) { synchronized (WifiUtil.class) { if (instance == null) { instance = new WifiUtil(context); } } } return instance; } public boolean isWifiApEnabled() { try { Method method = mWifiManager.getClass().getMethod("isWifiApEnabled"); method.setAccessible(true); return (Boolean) method.invoke(mWifiManager); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return false; } public String getLocalIPAddress() { WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); return intToIp(wifiInfo.getIpAddress()); } public String getServerIPAddress() { DhcpInfo mDhcpInfo = mWifiManager.getDhcpInfo(); return intToIp(mDhcpInfo.gateway); } private static String intToIp(int i) { return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + ((i >> 24) & 0xFF); } /** * @return 优先获取网卡地址 */ public static String getBroadcastAddress() { String broadcast = getBroadcastAddress("p2p"); if (broadcast == null) { return getBroadcastAddress("wlan0"); } return broadcast; } /** * @param netCardName 网卡名称 * @return 获取的广播地址 */ public static String getBroadcastAddress(String netCardName) { try { Enumeration eni = NetworkInterface .getNetworkInterfaces(); while (eni.hasMoreElements()) { NetworkInterface networkCard = eni.nextElement(); if (networkCard.getDisplayName().startsWith(netCardName)) { List ncAddrList = networkCard .getInterfaceAddresses(); Iterator ncAddrIterator = ncAddrList.iterator(); while (ncAddrIterator.hasNext()) { InterfaceAddress networkCardAddress = ncAddrIterator.next(); InetAddress address = networkCardAddress.getAddress(); if (!address.isLoopbackAddress()) { String hostAddress = address.getHostAddress(); if (hostAddress.indexOf(":") > 0) { // case : ipv6 continue; } else { // case : ipv4 String broadcastAddress = networkCardAddress.getBroadcast().getHostAddress(); return broadcastAddress; } } } } } } catch (Exception e) { e.printStackTrace(); } return null; } } ================================================ FILE: AppSocket/src/main/res/drawable/ic_launcher_background.xml ================================================ ================================================ FILE: AppSocket/src/main/res/drawable-v24/ic_launcher_foreground.xml ================================================ ================================================ FILE: AppSocket/src/main/res/mipmap-anydpi-v26/ic_launcher.xml ================================================ ================================================ FILE: AppSocket/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml ================================================ ================================================ FILE: AppSocket/src/main/res/values/colors.xml ================================================ #3F51B5 #303F9F #FF4081 ================================================ FILE: AppSocket/src/main/res/values/strings.xml ================================================ AndroidSocket ================================================ FILE: AppSocket/src/main/res/values/styles.xml ================================================ ================================================ FILE: AppSocket/src/test/java/melo/com/androidsocket/ExampleUnitTest.java ================================================ package melo.com.androidsocket; import org.junit.Test; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: README.md ================================================ # AndroidSocket 项目介绍地址: http://www.jianshu.com/p/61de9478c9aa ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "melo.com.app" minSdkVersion 21 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' implementation 'com.android.support:design:26.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' implementation project(':AppSocket') } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: app/src/androidTest/java/melo/com/app/ExampleInstrumentedTest.java ================================================ package melo.com.app; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumented test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("melo.com.app", appContext.getPackageName()); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/melo/com/app/MainActivity.java ================================================ package melo.com.app; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import melo.com.androidsocket.socket.SocketManager; public class MainActivity extends AppCompatActivity { @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.fab) FloatingActionButton fab; private SocketManager manager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); manager = SocketManager.getInstance(this); manager.startUdpConnection(); } @OnClick(R.id.fab) public void onViewClicked() { } @Override protected void onDestroy() { super.onDestroy(); manager.stopSocket(); } } ================================================ FILE: app/src/main/res/drawable/ic_launcher_background.xml ================================================ ================================================ FILE: app/src/main/res/drawable-v24/ic_launcher_foreground.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: app/src/main/res/layout/content_main.xml ================================================