前言:
最近客戶提出了一個這樣的需求,他們的apk想要獲取到我們rk3188板的參數和一些控制板卡的命令如(音量+、音量-、關機、重啓、亮度+、亮度-)等等。但是又不想讓他們的apk直接和板卡有任務關係,所以就採用到了這樣的辦法,採用sokcet局域網通信機制。把客戶的apk作爲socket服務端,然後再寫一個apk作爲socket客戶端,裝在同一臺機器上面,這樣就可以實現客戶的需求了。
步驟一:創建一個ClientServer Demo 並 編寫客戶端代碼
代碼裏面都有詳細註釋,寫在服務裏面的。
由於博主是用的以太網所以HOST地址填寫的:127.0.0.1 PORT地址隨便填寫的。
如果你們用的wifi或者手機共享網絡,HOST地址就填寫相應的址
MainSocketClientService.java
package com.android.clientserver; import android.app.Service; import android.content.Intent; import android.media.AudioManager; import android.os.IBinder; import android.support.annotation.Nullable; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.WeakReference; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** * Created by Administrator on 2018/5/19. */ public class MainSocketClientService extends Service { private static final String TAG = "MainSocketClientService"; private static final String HOST = "127.0.0.1"; private static final int PORT = 12345; private WeakReference<Socket> mSocket; private ReadThread mReadThread; private static SocketThread socketThread = null; private AudioManager mAudioManager; private double maxVolume; private synchronized SocketThread instance() { if (socketThread == null) { socketThread = new SocketThread(); } return socketThread; } private synchronized void destroyInstance() { if (socketThread != null) { socketThread = null; } } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "MainSocketClientService onCreate......"); mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); instance().start(); } public class SocketThread extends Thread { @Override public void run() { super.run(); initSocket(); } } /** * 初始化SocketReadThread */ private void initSocket() { try { Socket socket = new Socket(HOST, PORT); socket.setOOBInline(true); mSocket = new WeakReference<Socket>(socket); mReadThread = new ReadThread(socket); mReadThread.start(); // 每隔十秒發送一個心跳給服務端,判斷socket連接是否ok new Timer().schedule(new TimerTask() { @Override public void run() { String heartBeat = "{\"cmd\":\"heartbeat\"}" + "#end#" + "\t\t" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date().getTime()); boolean isSuccess = sendMsg(heartBeat); Log.d(TAG, "MainSocketClientService isSuccess = " + isSuccess); // 如果isSuccess返回false,就說明socket連接掉線,然後重連 if (!isSuccess) { Log.d(TAG, "MainSocketClientService socket斷開連接,重連socket......"); mReadThread.release(); new Thread(new Runnable() { @Override public void run() { initSocket(); } }).start(); } } }, 0, 5000); } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "MainSocketClientService initSocket IOException e = " + e.getMessage()); try { Thread.sleep(5000); initSocket(); } catch (InterruptedException e1) { e1.printStackTrace(); } } } /** * 接收來自服務器的數據 */ class ReadThread extends Thread { private WeakReference<Socket> mWeakSocket; private boolean isStart = true; public ReadThread(Socket socket) { mWeakSocket = new WeakReference<Socket>(socket); } public void release() { isStart = false; if (mWeakSocket != null) { releaseLastSocket(mWeakSocket); } } @Override public void run() { super.run(); Socket socket = mWeakSocket.get(); if (null != socket) { try { InputStream is = socket.getInputStream(); byte[] buffer = new byte[1024 * 4]; int length = 0; while (!socket.isClosed() && !socket.isInputShutdown() && isStart && ((length = is.read(buffer)) != -1)) { Log.d(TAG, "MainSocketClientService ReadThread socket = " + socket + "\r\n" + "length = " + length); if (length > 0) { String getServerMessage = new String(Arrays.copyOf(buffer, length)).trim(); Log.d(TAG, "MainSocketClientService ReadThread getServerMessage = " + getServerMessage); JSONObject jsonObject = new JSONObject(getServerMessage); String cmd = jsonObject.getJSONObject("data").getString("cmd"); switch (cmd) { case "increaseVoice":// 音量+ 100 Log.d(TAG, "MainSocketClientService increaseVoice......"); double increaseVolume = jsonObject.getJSONObject("data").getInt("increaseVolume"); mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) Math.floor(maxVolume * (increaseVolume / 100)), 0); break; case "reduceVoice":// 音量- 0 Log.d(TAG, "MainSocketClientService reduceVoice......"); double reduceVolume = jsonObject.getJSONObject("data").getInt("reduceVolume"); mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, (int) Math.floor(maxVolume * (reduceVolume / 100)), 0); break; case "shutdown":// 關機 Log.d(TAG, "MainSocketClientService shutdown......"); int shutdownTime = jsonObject.getJSONObject("data").getInt("shutdownTime"); String[] arrayShutDown = {"su", "-c", "reboot -p"}; try { Thread.sleep(shutdownTime * 1000); Runtime.getRuntime().exec(arrayShutDown); } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "MainSocketClientService shutdown IOException e = " + e.getMessage()); } catch (InterruptedException e) { e.printStackTrace(); } break; case "reboot":// 重啓機器 Log.d(TAG, "MainSocketClientService reboot......"); int rebootTime = jsonObject.getJSONObject("data").getInt("rebootTime"); String[] arrayReboot = {"su", "-c", "reboot"}; try { Thread.sleep(rebootTime * 1000); Runtime.getRuntime().exec(arrayReboot); } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "MainSocketClientService reboot IOException e = " + e.getMessage()); } catch (InterruptedException e) { e.printStackTrace(); } break; case "increaseBrightness":// 亮度+ 100 Log.d(TAG, "MainSocketClientService increaseBrightness......"); double addBrightnessValue = jsonObject.getJSONObject("data").getInt("addBrightnessValue"); break; case "reduceBrightness":// 亮度- 0 Log.d(TAG, "MainSocketClientService reduceBrightness......"); double reduceBrightnessValue = jsonObject.getJSONObject("data").getInt("reduceBrightnessValue"); break; case "machineParameters":// 獲取到板卡參數發送到服務端app Log.d(TAG, "MainSocketClientService machineParameters......"); String wifiMacAddress = DeviceUtils.getWlanMac(); String versionName = DeviceUtils.getVersionName(MainSocketClientService.this); int versionCode = DeviceUtils.getVersionCode(MainSocketClientService.this); String appName = DeviceUtils.getAppName(MainSocketClientService.this); JSONObject jsonObject1 = new JSONObject(); jsonObject1.put("wifiMacAddress", wifiMacAddress); jsonObject1.put("versionName", versionName); jsonObject1.put("versionCode", versionCode); jsonObject1.put("appName", appName); String machineParametersJsonData = jsonObject1.toString() + "#end#"; Log.d(TAG, "MainSocketClientService machineParametersJsonData = " + machineParametersJsonData); sendMsg(machineParametersJsonData); break; } } } } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "MainSocketClientService ReadThread IOException e = " + e.getMessage()); } catch (JSONException e) { e.printStackTrace(); Log.d(TAG, "MainSocketClientService ReadThread JSONException e = " + e.getMessage()); } } } } /** * 從客戶端app通過socket傳輸數據到服務端app * * @param msg * @return */ private boolean sendMsg(final String msg) { if (null == mSocket || null == mSocket.get()) { Log.d(TAG, "MainSocketClientService mSocket爲空或者mSocket.get()爲空......"); return false; } final Socket soc = mSocket.get(); if (!soc.isClosed() && !soc.isOutputShutdown()) { new Thread(new Runnable() { @Override public void run() { try { OutputStream os = soc.getOutputStream(); String sendMessage = msg + "\r\n"; if (sendMessage != null && !"".equals(sendMessage)) { os.write(sendMessage.getBytes()); os.flush(); } } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "MainSocketClientService sendMsg IOException e = " + e.getMessage()); } } }).start(); } else { Log.d(TAG, "MainSocketClientService soc.isClosed並且soc.isOutputShutdown()......"); return false; } return true; } private void releaseLastSocket(WeakReference<Socket> mSocket) { // try{ // if(null != mSocket){ // Socket sk = mSocket.get(); // if(sk == null){ // return; // } // if(!sk.isClosed()){ // sk.close(); // } // sk = null; // mSocket = null; // } // }catch (IOException e){ // e.printStackTrace(); // Log.d(TAG,"MainSocketClientService releaseLastSocket e= " + e.getMessage() ); // } try { if (mSocket != null) { Socket sk = mSocket.get(); sk.close(); } } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "MainSocketClientService releaseLastSocket e= " + e.getMessage()); } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); if (mReadThread != null) { mReadThread.release(); } if (mSocket != null) { releaseLastSocket(mSocket); } destroyInstance(); } }
這個是獲取設備信息的工具類,只是作測試用的
package com.android.clientserver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.util.Log; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Created by Administrator on 2018/5/19. */ public class DeviceUtils { private static final String TAG = "DeviceUtils"; public static String getWlanMac() { try { Log.d(TAG, "getWlanMac:" + loadFileAsString("/sys/class/net/wlan0/address").toUpperCase().substring(0, 17)); return loadFileAsString("/sys/class/net/wlan0/address").toUpperCase().substring(0, 17); } catch (Exception e) { Log.e(TAG, "open sys/class/net/eth0/address failed : " + e); return ""; } } private static String loadFileAsString(String filePath) throws IOException { StringBuffer sb = new StringBuffer(1000); BufferedReader br = new BufferedReader(new FileReader(filePath)); char[] buf = new char[1024]; int numRead = 0; while ((numRead = br.read(buf)) != -1) { String readData = String.valueOf(buf, 0, numRead); sb.append(readData); } br.close(); return sb.toString(); } /** * 獲取版本名稱 * * @param context 上下文 * @return 版本名稱 */ public static String getVersionName(Context context) { // 獲取包管理器 PackageManager pm = context.getPackageManager(); // 獲取包信息 try { PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0); // 返回版本名稱 return packageInfo.versionName; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return null; } /** * 獲取版本號 * * @param context 上下文 * @return 版本號 */ public static int getVersionCode(Context context) { // 獲取包管理器 PackageManager pm = context.getPackageManager(); // 獲取包信息 try { PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0); // 返回版本號 return packageInfo.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return 0; } /** * 獲取App的名稱 * * @param context 上下文 * @return App名稱 */ public static String getAppName(Context context) { // 獲取包管理器 PackageManager pm = context.getPackageManager(); // 獲取包信息 try { PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0); // 獲取應用信息 ApplicationInfo applicationInfo = packageInfo.applicationInfo; //獲取labelRes int labelRes = applicationInfo.labelRes; // 返回App的名稱 return context.getResources().getString(labelRes); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return null; } }
步驟二:創建一個SocketServer Demo 並 編寫服務端代碼
MainSocketServer.java
package com.android.socketserver; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.TextView; /** * Created by Administrator on 2018/5/19. */ public class MainSocketServer extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "MainSocketServer"; String abc = "{ \"data\": {\"cmd\": \"reboot\", \"time\": 3}}"; private Button increase_voice_btn; private Button reduce_voice_btn; private Button shutdown_btn; private Button reboot_btn; private Button increase_brightness_btn; private Button reduce_brightness_btn; private Button display_machine_parameters_btn; private TextView display_machine_parameters_tv; //啓動服務端端口服務端IP private SocketServer server = new SocketServer(12345); private StringBuilder stringBuilder; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); stringBuilder = new StringBuilder(); // socket服務端開始監聽 server.beginListen(); // socket收到消息線程 SocketServer.serverHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); stringBuilder.append(msg.obj.toString()); stringBuilder.append("\r\n"); display_machine_parameters_tv.setText(stringBuilder); } }; } private void initView() { increase_voice_btn = (Button) findViewById(R.id.increase_voice_btn); reduce_voice_btn = (Button) findViewById(R.id.reduce_voice_btn); shutdown_btn = (Button) findViewById(R.id.shutdown_btn); reboot_btn = (Button) findViewById(R.id.reboot_btn); increase_brightness_btn = (Button) findViewById(R.id.increase_brightness_btn); reduce_brightness_btn = (Button) findViewById(R.id.reduce_brightness_btn); display_machine_parameters_btn = (Button) findViewById(R.id.display_machine_parameters_btn); display_machine_parameters_tv = (TextView) findViewById(R.id.display_machine_parameters_tv); initListener(); } private void initListener() { increase_voice_btn.setOnClickListener(this); reduce_voice_btn.setOnClickListener(this); shutdown_btn.setOnClickListener(this); reboot_btn.setOnClickListener(this); increase_brightness_btn.setOnClickListener(this); reduce_brightness_btn.setOnClickListener(this); display_machine_parameters_btn.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.increase_voice_btn: // 發送指令,把音量調成100 String increaseVoice = "{ \"data\": { \"cmd\": \"increaseVoice\", \"increaseVolume\":100}}" + "#end#"; server.sendMessage(increaseVoice); break; case R.id.reduce_voice_btn: // 發送指令,把音量調成0 String reduceVoice = "{ \"data\": { \"cmd\": \"reduceVoice\", \"reduceVolume\":0}}" + "#end#"; server.sendMessage(reduceVoice); break; case R.id.shutdown_btn: // 發送指令 3秒後關閉機器 String shutdown = "{ \"data\": { \"cmd\": \"shutdown\", \"shutdownTime\":3}}" + "#end#"; server.sendMessage(shutdown); break; case R.id.reboot_btn: // 發送指令 3秒後重啓機器 String reboot = "{ \"data\": { \"cmd\": \"reboot\", \"rebootTime\":3}}" + "#end#"; server.sendMessage(reboot); break; case R.id.increase_brightness_btn: // 發送指令,把亮度調成100 String increaseBrightness = "{ \"data\": { \"cmd\": \"increaseBrightness\", \"addBrightnessValue\":100}}" + "#end#"; server.sendMessage(increaseBrightness); break; case R.id.reduce_brightness_btn: // 發送指令,把亮度調成100 String reduceBrightness = "{ \"data\": { \"cmd\": \"reduceBrightness\", \"reduceBrightnessValue\":0}}" + "#end#"; server.sendMessage(reduceBrightness); break; case R.id.display_machine_parameters_btn: // 發送指令 獲取板卡參數 String machineParameters = "{ \"data\": { \"cmd\": \"machineParameters\"}}" + "#end#"; server.sendMessage(machineParameters); break; } } }
SocketServer封裝類
package com.android.socketserver; import android.os.Handler; import android.os.Message; import android.util.Log; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Arrays; /** * Created by Administrator on 2018/5/19. */ public class SocketServer { private static final String TAG = "SocketServer"; private ServerSocket server; private Socket mSocket; private InputStream in; private String getClientData = ""; private boolean isClient = false; public static Handler serverHandler; /** * 初始化服務端 * * @param port */ public SocketServer(int port) { try { server = new ServerSocket(port); isClient = true; } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "SocketServer IOException e = " + e.getMessage()); } } /** * socket監聽數據 */ public void beginListen() { new Thread(new Runnable() { @Override public void run() { try { Log.d(TAG, "SocketServer beginListen......"); // 接受請求 if (server != null && isClient == true) { mSocket = server.accept(); } // 得到輸入流 in = mSocket.getInputStream(); // 實現數據循環接收 while (mSocket.isConnected()) { byte[] buffer = new byte[1024 * 4]; int length = in.read(buffer); getClientData = new String(Arrays.copyOf(buffer, length)).trim(); Log.d(TAG, "SocketServer beginListen getClientData = " + getClientData); if (getClientData != null && !"".equals(getClientData) && getClientData != "exit") { returnMessage(getClientData); } else if (getClientData == null || getClientData == "exit") { break; } } } catch (IOException e) { Log.d(TAG, "SocketServer beginListen IOException e = " + e.getMessage()); mSocket.isClosed(); } } }).start(); } /** * socket服務端發送指令給客戶端 * * @param toClientCommand */ public void sendMessage(final String toClientCommand) { Thread thread = new Thread(new Runnable() { @Override public void run() { try { if (mSocket != null && !mSocket.isClosed() && toClientCommand != null) { Log.d(TAG, "SocketServer sendMessage toClientCommand = " + toClientCommand); PrintWriter out = new PrintWriter(mSocket.getOutputStream()); out.print(toClientCommand); out.flush(); } } catch (IOException e) { e.printStackTrace(); Log.d(TAG, "SocketServer sendMessage IOException e = " + e.getMessage()); } } }); thread.start(); } /** * socket服務端得到返回的數據併發送到主界面 * * @param getClientData */ public void returnMessage(String getClientData) { Message msg = new Message(); msg.obj = getClientData; serverHandler.sendMessage(msg); } }