Socket 传输文件带进度(设备开热点,形成局域网)
源码地址 : https://github.com/shotter0/SocketUpdateFile.git
以前写过一片UDP 文件传输的,UDP传输效率快,有目共睹的,一般的投屏(乐播。eSHARE)都用的是UDP传输,遇到的项目。对文件完整性要求比较高,知道TCP.UDP的同学应该都知道 ,不是很清楚的去百度一下,这里我选择使用TCP 进行文件传输,
这样两台设备在局域网的情况下 ,就可以直接通讯了 ,后来经过测试。传输的速度不是很理想 ,我下载了茄子快传,那个速度正是我想要的 ,茄子快传就使用了设备开热点,另一台设备去连接那个热点,然后进行文件传输
当时我试了很久,都不知道是怎么实现的,去git上扒了一份代码 。估计很多人都知道这个XO快传,就是仿茄子快传来的。
https://github.com/mayubao/KuaiChuan
github上的项目是使用UDP进行文件传输的,我参考了,他里面的设备开启热点,设备连接,的方法 ,其实也没什么。设备开启热点之后 ,设备的IP地址是固定的,然后。。。。
直接看效果把 。
服务端(设备开热点)效果,为了方便连接,我直接使用二维码扫描进行绑定的,这样更方便用户操作
二维码里面的信息,包含了IP地址和wifi信息,用来判断手机和设备是不是同一个wifi提示用户,持续更新中,后边会添加局域网所有设备进行传输
2:手机端的界面,我使用了数据库,用来保存已经连接过的设备,便于下次直接建立连接
客户端,服务端的切换处
修改 TAG_APP的值 ,直接运行,就是服务端,手机端的代码了
package com.cdl.socket.config; import android.os.Environment; /*** * 常量配置类 */ public class SocketConfig { public static final int TAG_SERVER = 0; public static final int TAG_CLIENT = 1; public static final int TAG_TEST = 2; /*** * TAG_APP * 根据设备选中软件 */ public static int TAG_APP = TAG_SERVER; /*** * 服务端,设备端通讯端口号 */ public static final int SERVER_PORT = 9865; public static final String IP_ADDRESS_HOT_WIFI = "192.168.43.1"; /*** * 文件接收完毕,发一个通知出来,用来刷新界面 */ public static final String RECEIVER_FILE_SUCCESS = "com.cdl.socket.RECEIVER_FILE_SUCCESS"; public static final String authorities = "com.cdl.socket.fileprovider"; /*** * 二维码扫描返回的Code */ public static final int REQUEST_CODE = SERVER_PORT + 1; /*** * 文件选择器返回的返回的标志 */ public static final int FILE_CHOOICE_BACK = REQUEST_CODE + 1; /*** * App根目录 */ public static final String BASE_SD_PATH = Environment.getExternalStorageDirectory().getPath() + "/mirror"; /*** * 存放二维码的路径 */ public static final String ER_CODE_PATH = BASE_SD_PATH + "/qr"; /*** * 用于存放接受文件的路径的 */ public static final String FILE_RECEIVER_PATH = BASE_SD_PATH + "/filereceive"; /*** * 二维码存放的路径 */ public static final String ERCODE_SAVE_PATH = ER_CODE_PATH + "/SocketBind.png"; }
服务端接收文件的线程 , 传输文件流,第一行传输文件名字和文件的大小,用来界面显示
package com.cdl.socket.thread; import android.content.Intent; import android.os.Handler; import android.util.Log; import com.cdl.socket.config.SocketConfig; import com.cdl.socket.inteface.ReceiveFileListener; import com.cdl.socket.server.ServerReceiveEntity; import com.util.NetWorkUtils; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class ServerReceiveFileRunnable implements Runnable { private ServerSocket server; ReceiveFileListener listener; boolean isReceive = true; private Handler handler = new Handler(); public ServerReceiveFileRunnable(ReceiveFileListener listener) { this.listener = listener; try { server = new ServerSocket(SocketConfig.SERVER_PORT); } catch (Exception e) { isReceive = false; backInfo(ServerReceiveEntity.RECEIVER_ERROR, "", "", 0, 0, e.toString()); } } @Override public void run() { while (isReceive) { ReceiveFile(); } } void ReceiveFile() { try { Socket name = server.accept(); InputStream nameStream = name.getInputStream(); InputStreamReader streamReader = new InputStreamReader(nameStream); BufferedReader br = new BufferedReader(streamReader); String nameLength = br.readLine(); Log.e("receiveFile", "===nameLength:" + nameLength); String fileName = nameLength.substring(0, nameLength.indexOf(":")); long fileLength = Long.parseLong(nameLength.substring(nameLength.indexOf(":") + 1, nameLength.length())); String savePath = SocketConfig.FILE_RECEIVER_PATH + "/" + fileName; Log.e("receiveFile", "===接收文件的名字:" + fileName + " //" + fileLength); br.close(); streamReader.close(); nameStream.close(); name.close(); backInfo(ServerReceiveEntity.RECEIVER_START, fileName, savePath, 0, fileLength, "开始接收文件"); Socket data = server.accept(); InputStream dataStream = data.getInputStream(); File fileDir = new File(savePath); if (fileDir.exists()) { fileDir.delete(); } fileDir.createNewFile(); FileOutputStream file = new FileOutputStream(savePath, false); byte[] buffer = new byte[1024]; int size = -1; long sum = 0; while ((size = dataStream.read(buffer)) != -1) { file.write(buffer, 0, size); sum += size; Log.e("====", "++++++" + NetWorkUtils.bytes2kb(sum) + " /" + NetWorkUtils.bytes2kb(fileLength)); backInfo(ServerReceiveEntity.RECEIVER_PROGRESS, fileName, savePath, sum, fileLength, "接收中"); } file.close(); dataStream.close(); data.close(); backInfo(ServerReceiveEntity.RECEIVER_SUCCESS, fileName, savePath, fileLength, fileLength, "接收成功"); } catch (Exception e) { isReceive = false; backInfo(ServerReceiveEntity.RECEIVER_ERROR, "", "", 0, 0, e.toString()); } } public void backInfo(final int receive_state, final String fileName, final String fileSavePath, final long fileHasReceive, final long fileTotalLength, final String receiveDesc) { handler.post(new Runnable() { @Override public void run() { ServerReceiveEntity serverReceiveEntity = new ServerReceiveEntity(receive_state, fileName, fileSavePath, fileHasReceive, fileTotalLength, receiveDesc); listener.receiveFileState(serverReceiveEntity); } }); } public void stopReceiveFile() { try { isReceive = false; if (server != null) { server.close(); } } catch (Exception e) { } } }
用来处理服务端消息的工具类
里面设计到权限和android 7.0的文件读取相关,详细的代码还是直接从git上面下载把 。
package com.cdl.socket.server; import android.Manifest; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.support.v4.content.FileProvider; import android.util.Log; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.cdl.socket.R; import com.cdl.socket.activity.SocketServer; import com.cdl.socket.config.SocketConfig; import com.cdl.socket.inteface.ReceiveFileListener; import com.cdl.socket.thread.ServerReceiveFileRunnable; import com.cdl.socket.util.FileUtil; import com.cdl.socket.util.QRCodeUtil; import com.cdl.socket.view.GridButton; import java.io.File; import java.util.ArrayList; import java.util.List; import me.weyye.hipermission.HiPermission; import me.weyye.hipermission.PermissionCallback; import me.weyye.hipermission.PermissonItem; /** * */ public class SocketReceiveUtil implements QRCodeUtil.ErCodeBackListener { Activity context; GridButton grid_button_receiver; ImageView iv_ercode_bind; ServerReceiveView serverReceiveView; private QRCodeUtil qrCodeUtil = null; //二维码生成工具类 public SocketReceiveUtil(Activity context, ServerReceiveView serverReceiveView) { this.context = context; this.serverReceiveView = serverReceiveView; getView(); } private void getView() { iv_ercode_bind = serverReceiveView.getErCodeImageview(); grid_button_receiver = serverReceiveView.getGridButton(); } ServerReceiveFileRunnable receiveFileRunnable = null; public void receiveMessage() { FileUtil.creatPathNotExcit(); receiveFileRunnable = new ServerReceiveFileRunnable(new ReceiveFileListener() { @Override public void receiveFileState(ServerReceiveEntity mServerReceiveEntity) { Log.e("receiveFile", "=======" + mServerReceiveEntity.toString()); dealReceiveInfo(mServerReceiveEntity); } }); Thread thread = new Thread(receiveFileRunnable); thread.start(); } /*** * 停止接收文件 */ public void stopReceiveFile() { if (receiveFileRunnable != null) { receiveFileRunnable.stopReceiveFile(); } } /*** * 处理接收的文件相关信息 * @param mServerReceiveEntity */ private void dealReceiveInfo(ServerReceiveEntity mServerReceiveEntity) { int state = mServerReceiveEntity.getReceive_state(); String fileName = mServerReceiveEntity.getFileName(); String fileSavePath = mServerReceiveEntity.getFileSavePath(); long fileHasReceive = mServerReceiveEntity.getFileHasReceive(); long fileTotalLength = mServerReceiveEntity.getFileTotalLength(); String receiveDesc = mServerReceiveEntity.getReceiveDesc(); switch (state) { case ServerReceiveEntity.RECEIVER_START: grid_button_receiver.updateProgress(fileName, 0, fileTotalLength); break; case ServerReceiveEntity.RECEIVER_PROGRESS: grid_button_receiver.updateProgress(fileName, fileHasReceive, fileTotalLength); // Intent intent = new Intent(); // intent.setAction(SocketConfig.RECEIVER_FILE_SUCCESS); // context.sendBroadcast(intent); // try { // File file = new File(fileSavePath); // long fileSaveLength = file.length(); // grid_button_receiver.updateProgress(fileName, fileSaveLength, fileTotalLength); // } catch (Exception e) { // serverReceiveView.showToast(e.toString()); // } break; case ServerReceiveEntity.RECEIVER_SUCCESS: grid_button_receiver.resetState(); serverReceiveView.showToast(receiveDesc); break; case ServerReceiveEntity.RECEIVER_ERROR: grid_button_receiver.resetState(); serverReceiveView.showToast(receiveDesc); break; } } /*** * 打开系统的文件管理器 */ public void jumpFileManager() { File file = new File(SocketConfig.FILE_RECEIVER_PATH); File parentFlie = new File(file.getParent()); Intent intent = new Intent(Intent.ACTION_GET_CONTENT); Uri fileUrl = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //7.0执行该方法 fileUrl = FileProvider.getUriForFile(context, SocketConfig.authorities, parentFlie); } else { //7.0以下手机系统执行这个方法 fileUrl = Uri.fromFile(parentFlie); } intent.setDataAndType(fileUrl, "*/*"); intent.addCategory(Intent.CATEGORY_OPENABLE); context.startActivity(intent); } public void createErCodeImage(String ipAddress) { if (qrCodeUtil == null) { qrCodeUtil = new QRCodeUtil(context, this); } try { File file = new File(SocketConfig.ERCODE_SAVE_PATH); if (file.exists()) { file.delete(); } file.createNewFile(); qrCodeUtil.createErCode(ipAddress, SocketConfig.ERCODE_SAVE_PATH); } catch (Exception e) { serverReceiveView.showToast(e.toString()); } } /*** * 检查app需要的权限 */ public void checkAppPermission() { List<PermissonItem> permissonItems = new ArrayList<PermissonItem>(); permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); HiPermission.create(context) .permissions(permissonItems) .checkMutiPermission(new PermissionCallback() { @Override public void onClose() { } @Override public void onFinish() { } @Override public void onDeny(String permisson, int position) { } @Override public void onGuarantee(String permisson, int position) { } }); } @Override public void createErCodeState(String errorDes, boolean isCreate, String filePath) { Log.e("ercode", "=====" + errorDes + " //" + isCreate + " / " + filePath); if (isCreate) { // Glide.with(context).load(filePath).diskCacheStrategy(DiskCacheStrategy.NONE).into(iv_ercode_bind); Bitmap bitmap = BitmapFactory.decodeFile(filePath); iv_ercode_bind.setImageBitmap(bitmap); } else { iv_ercode_bind.setBackgroundResource(R.mipmap.ic_launcher); serverReceiveView.showToast(errorDes); } } }
服务端界面显示 , 界面主要用来更新UI ,开关WIFI,和开关热点,以及一些其他的异常
package com.cdl.socket.activity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.cdl.socket.R; import com.cdl.socket.config.SocketConfig; import com.cdl.socket.croe.util.ApMgr; import com.cdl.socket.croe.util.WifiMgr; import com.cdl.socket.server.ServerReceiveView; import com.cdl.socket.server.SocketReceiveUtil; import com.cdl.socket.util.FileUtil; import com.cdl.socket.util.SharedPerManager; import com.cdl.socket.view.GridButton; import com.cdl.view.dialog.OridinryDialog; import com.com.view.customview.TopBarView; import com.com.view.customview.WaitDialogUtil; import com.util.BlueTeethUtil; import com.view.MyToastView; import org.json.JSONObject; public class SocketServer extends Activity implements ServerReceiveView, View.OnClickListener { private TextView tv_port; private ImageView iv_ercode_bind; Button btn_junp_filepath; GridButton grid_button_receiver; SocketReceiveUtil socketReceiveUtil; WaitDialogUtil waitDialoUtil; private Handler handler = new Handler(); TopBarView top_server; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_server); FileUtil.creatPathNotExcit(); initView(); } private void initView() { waitDialoUtil = new WaitDialogUtil(SocketServer.this); grid_button_receiver = (GridButton) findViewById(R.id.grid_button_receiver); top_server = (TopBarView) findViewById(R.id.top_server); iv_ercode_bind = (ImageView) findViewById(R.id.iv_ercode_bind); tv_port = (TextView) findViewById(R.id.tv_port); tv_port.setText("端口号: " + SocketConfig.SERVER_PORT); btn_junp_filepath = (Button) findViewById(R.id.btn_junp_filepath); btn_junp_filepath.setOnClickListener(this); socketReceiveUtil = new SocketReceiveUtil(SocketServer.this, this); socketReceiveUtil.checkAppPermission(); socketReceiveUtil.receiveMessage(); initHotWifi(); } private void initHotWifi() { waitDialoUtil.show("开启热点中"); handler.postDelayed(new Runnable() { @Override public void run() { waitDialoUtil.dismiss(); if (ApMgr.isApOn(SocketServer.this)) { MyToastView.getInstance().Toast(SocketServer.this, "创建WIFI热点成功"); } else { MyToastView.getInstance().Toast(SocketServer.this, "创建WIFI热点失败"); } } }, 2000); /*** * 0:判断wifi是否打开,打开就直接关闭 * 1:判断AP是否打开 * 2:没打开,就直接打开 * 2.5:显示当前热点的名字 wifi * 3:设备显示 192.168.43.1 IP地址 * 4:二维码显示 wifi + ip */ boolean isWifiOpen = WifiMgr.getInstance(SocketServer.this).isWifiEnable(); if (isWifiOpen) { WifiMgr.getInstance(SocketServer.this).closeWifi(); } if (!ApMgr.isApOn(SocketServer.this)) { String bluethCode = BlueTeethUtil.getBlueToothCode(); bluethCode = bluethCode.substring(bluethCode.length() - 4, bluethCode.length()); boolean isCreate = ApMgr.configApState(SocketServer.this, "MirrorMagic_" + bluethCode); if (isCreate) { updateWifiView(); } } else { updateWifiView(); } } public void updateWifiView() { try { String hotWifiIp = SocketConfig.IP_ADDRESS_HOT_WIFI; top_server.setTitleText("IP : " + SocketConfig.IP_ADDRESS_HOT_WIFI); String bluethCode = BlueTeethUtil.getBlueToothCode(); String wifiName = "MirrorMagic_" + (bluethCode.substring(bluethCode.length() - 4, bluethCode.length())); JSONObject jsonObject = new JSONObject(); jsonObject.put("wifi_name", wifiName); jsonObject.put("ip_address", hotWifiIp); String erCodeInfo = jsonObject.toString(1); socketReceiveUtil.createErCodeImage(erCodeInfo); //创建二维码 } catch (Exception e) { } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_junp_filepath: // socketReceiveUtil.jumpFileManager(); //跳转到文件接收的目录 Intent intent = new Intent(SocketServer.this, FileListActivity.class); intent.putExtra(FileListActivity.PATH_SEARCH, SocketConfig.FILE_RECEIVER_PATH); startActivity(intent); break; } } @Override protected void onResume() { super.onResume(); } //====================================================================== // @Override public ImageView getErCodeImageview() { return iv_ercode_bind; } @Override public GridButton getGridButton() { return grid_button_receiver; } @Override public void showToast(String toast) { MyToastView.getInstance().Toast(SocketServer.this, toast); } OridinryDialog oridinryDialog; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (oridinryDialog == null) { oridinryDialog = new OridinryDialog(SocketServer.this, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight()); } oridinryDialog.show("是否退出软件?", "确定", "取消"); oridinryDialog.setOnDialogClickListener(new OridinryDialog.OridinryDialogClick() { @Override public void sure() { closeAp(); } @Override public void noSure() { } }); } return super.onKeyDown(keyCode, event); } private void closeAp() { waitDialoUtil.show("关闭热点中"); handler.postDelayed(new Runnable() { @Override public void run() { waitDialoUtil.dismiss(); boolean isWifiOpen = WifiMgr.getInstance(SocketServer.this).isWifiEnable(); if (!isWifiOpen) { WifiMgr.getInstance(SocketServer.this).openWifi(); } boolean isOpen = ApMgr.isApOn(SocketServer.this); if (!isOpen) { //关闭就退出 finish(); } else { //未关闭,跳转到关闭页面 startActivity(new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS)); showToast("热点关闭失败,跳转到系统设置"); } } }, 2000); boolean isOpen = ApMgr.isApOn(SocketServer.this); if (isOpen) { ApMgr.disableAp(SocketServer.this); } } @Override protected void onDestroy() { super.onDestroy(); try { if (socketReceiveUtil != null) { socketReceiveUtil.stopReceiveFile(); } if (handler != null) { handler.removeMessages(0); } } catch (Exception e) { } } }
手机端代码
手机端发送文件线程,这些代码都大同小异
package com.cdl.socket.thread; import android.os.Handler; import android.util.Log; import com.cdl.socket.config.SocketConfig; import com.cdl.socket.inteface.MessageSendFileListener; import com.cdl.socket.util.SharedPerManager; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; /** * 发送文件线程 * Created by cdl on 2018/2/26. */ public class ClienSendFileRunnable implements Runnable { String fileName; String filePath; String ipAddress; MessageSendFileListener listener; private Handler handler = new Handler(); long fileTotalSize = 0; public ClienSendFileRunnable(String ipAddress, String fileName, String filePath, MessageSendFileListener listener) { this.fileName = fileName; this.ipAddress = ipAddress; this.filePath = filePath; this.listener = listener; File file = new File(filePath); fileTotalSize = file.length(); } Socket socketDate = null; OutputStream outputData = null; FileInputStream fileInput = null; @Override public void run() { try { Socket name = new Socket(ipAddress, SocketConfig.SERVER_PORT); OutputStream outputName = name.getOutputStream(); OutputStreamWriter outputWriter = new OutputStreamWriter(outputName); BufferedWriter bwName = new BufferedWriter(outputWriter); bwName.write(fileName + ":" + fileTotalSize); bwName.close(); outputWriter.close(); outputName.close(); name.close(); backMessageInfo(MessageSendFileListener.SEND_START, 0, 0, "开始传输"); socketDate = new Socket(ipAddress, SocketConfig.SERVER_PORT); outputData = socketDate.getOutputStream(); fileInput = new FileInputStream(filePath); int size = -1; long sum = 0; byte[] buffer = new byte[1024]; while ((size = fileInput.read(buffer, 0, 1024)) != -1) { outputData.write(buffer, 0, size); sum += buffer.length; Log.e("write", "====" + sum); backMessageInfo(MessageSendFileListener.SEND_PROGRESS, (int) (sum * 100 / fileTotalSize), sum, "传输中"); } outputData.close(); fileInput.close(); socketDate.close(); backMessageInfo(MessageSendFileListener.SEND_SUCCESS, 100, fileTotalSize, "传输完成"); } catch (Exception e) { backMessageInfo(MessageSendFileListener.SEND_ERROR, 0, 0, e.toString()); } } private void backMessageInfo(final int sendState, final int progress, final long fileLength, final String stateDesc) { handler.post(new Runnable() { @Override public void run() { listener.sendFileState(sendState, progress, fileLength, stateDesc); } }); } /*** * 关闭传输 */ public void stopSendFile() { try { if (socketDate != null) { socketDate.close(); } if (outputData != null) { outputData.close(); } if (fileInput != null) { fileInput.close(); } } catch (Exception e) { } } }
客户端工具类,业务量不是很大 ,所以没有使用一些设计模式,框架之类的,
package com.cdl.socket.client; import android.app.Activity; import android.util.Log; import android.widget.Toast; import com.cdl.socket.activity.main.MainClientUtil; import com.cdl.socket.db.DbManager; import com.cdl.socket.inteface.MessageSendFileListener; import com.cdl.socket.util.SharedPerManager; import com.cdl.socket.view.MainView; import com.cdl.view.dialog.FileSendDialog; import com.cdl.view.dialog.OridinryDialog; import com.util.NetWorkUtils; /**** * 客户端主界面工具类 */ public class MainParsener implements MessageSendFileListener { Activity context; MainView mainView; FileSendDialog dialog; private OridinryDialog oridinryDialog; MainClientUtil mainClicntUtil; public MainParsener(Activity context, MainView mainView) { this.mainView = mainView; this.context = context; mainClicntUtil = new MainClientUtil(context, this); getView(); } private void getView() { dialog = new FileSendDialog(context, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight()); dialog.setOnCacleSendFileListener(new FileSendDialog.FileSendDialogListener() { @Override public void clickCacle() { //取消发送文件 stopSendFile(); } }); } /*** * 检查Sd卡权限,并去选择图片 */ public void checkSdcardPermission(String ipAddress) { mainClicntUtil.checkSdcardPermission(ipAddress); } /*** * 检查相机权限,并去扫描文字 */ public void goToScan() { if (!NetWorkUtils.isNetworkConnected(context)) { mainView.showTaost("网络未连接,请检查"); return; } mainClicntUtil.checkCameraPermission(); } /*** * 文件发送累 * @param ipAddress * @param filePath */ public void sendFileMessage(String ipAddress, String filePath) { mainClicntUtil.sendFileMessage(ipAddress, filePath); } /*** * 取消文件发送 */ public void stopSendFile() { mainClicntUtil.stopSendMessage(); } /*** * 检查App需要的权限 */ public void checkAppPermission() { mainClicntUtil.checkAppPermission(); } public void delBindInfo(final String delInfo) { if (oridinryDialog == null) { oridinryDialog = new OridinryDialog(context, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight()); } oridinryDialog.show("是否删除该条数据", "删除", "取消"); oridinryDialog.setOnDialogClickListener(new OridinryDialog.OridinryDialogClick() { @Override public void sure() { if (DbManager.delBindInfo(delInfo)) { mainView.showTaost("删除数据成功"); mainView.refreshDbInfo(true); } else { mainView.refreshDbInfo(false); mainView.showTaost("删除数据失败"); } } @Override public void noSure() { } }); } /*** * 文件发送状态 * @param state * @param progress * @param stateDesc */ @Override public void sendFileState(int state, int progress, long sendLength, String stateDesc) { Log.e("SENDfILE", "=====" + state + " /" + progress + " /" + stateDesc); switch (state) { case MessageSendFileListener.SEND_START: if (dialog != null) { dialog.showDialog("准备发送文件", "取消发送"); } break; case MessageSendFileListener.SEND_PROGRESS: if (dialog != null) { dialog.updateSendProgress(NetWorkUtils.bytes2kb(sendLength), progress); } break; case MessageSendFileListener.SEND_SUCCESS: mainView.showTaost("传输成功"); dialog.dissmiss(); break; case MessageSendFileListener.SEND_ERROR: Toast.makeText(context, stateDesc, Toast.LENGTH_SHORT).show(); dialog.dissmiss(); break; } } }
package com.cdl.socket.activity.main; import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.cdl.socket.R; import com.cdl.socket.config.SocketConfig; import com.cdl.socket.inteface.MessageSendFileListener; import com.cdl.socket.thread.ClienSendFileRunnable; import com.uuzuche.lib_zxing.activity.CaptureActivity; import java.io.File; import java.util.ArrayList; import java.util.List; import me.weyye.hipermission.HiPermission; import me.weyye.hipermission.PermissionCallback; import me.weyye.hipermission.PermissonItem; /** * Created by jsjm on 2018/3/3. */ public class MainClientUtil { Activity context; MessageSendFileListener listenerBack; public MainClientUtil(Activity context, MessageSendFileListener listenerBack) { this.listenerBack = listenerBack; this.context = context; } public void stopSendMessage() { if (clienSendFileRunnable != null) { clienSendFileRunnable.stopSendFile(); } } ClienSendFileRunnable clienSendFileRunnable = null; public void sendFileMessage(String ipAddress, String filePath) { try { File file = new File(filePath); String fileName = file.getName(); clienSendFileRunnable = new ClienSendFileRunnable(ipAddress, fileName, filePath, new MessageSendFileListener() { @Override public void sendFileState(int state, int progress, long sendFileState, String stateDesc) { listenerBack.sendFileState(state, progress, sendFileState, stateDesc); } }); Thread thread = new Thread(clienSendFileRunnable); thread.start(); } catch (Exception e) { listenerBack.sendFileState(MessageSendFileListener.SEND_ERROR, 0, 0, e.toString()); } } /*** * 检查Sd卡权限,并去选择图片 */ public void checkSdcardPermission(String ipAddress) { if (TextUtils.isEmpty(ipAddress)) { Toast.makeText(context, "IP地址为空,请检查", Toast.LENGTH_SHORT).show(); return; } List<PermissonItem> permissonItems = new ArrayList<PermissonItem>(); permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); HiPermission.create(context) .permissions(permissonItems) .checkMutiPermission(new PermissionCallback() { @Override public void onClose() { } @Override public void onFinish() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); //intent.setType(“image/*”);//选择图片 //intent.setType(“audio/*”); //选择音频 //intent.setType(“video/*”); //选择视频 (mp4 3gp 是android支持的视频格式) //intent.setType(“video/*;image/*”);//同时选择视频和图片 intent.setType("*/*");//无类型限制 intent.addCategory(Intent.CATEGORY_OPENABLE); context.startActivityForResult(intent, SocketConfig.FILE_CHOOICE_BACK); } @Override public void onDeny(String permisson, int position) { } @Override public void onGuarantee(String permisson, int position) { } }); } /*** * 检查相机权限,并去扫描文字 */ public void checkCameraPermission() { List<PermissonItem> permissonItems = new ArrayList<PermissonItem>(); permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); HiPermission.create(context) .permissions(permissonItems) .checkMutiPermission(new PermissionCallback() { @Override public void onClose() { } @Override public void onFinish() { Intent intent = new Intent(context, CaptureActivity.class); context.startActivityForResult(intent, SocketConfig.REQUEST_CODE); } @Override public void onDeny(String permisson, int position) { } @Override public void onGuarantee(String permisson, int position) { } }); } public void checkAppPermission() { List<PermissonItem> permissonItems = new ArrayList<PermissonItem>(); permissonItems.add(new PermissonItem(Manifest.permission.CAMERA, "照相机", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.READ_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); permissonItems.add(new PermissonItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "SD卡权限", R.drawable.permission_ic_memory)); HiPermission.create(context) .permissions(permissonItems) .checkMutiPermission(new PermissionCallback() { @Override public void onClose() { } @Override public void onFinish() { } @Override public void onDeny(String permisson, int position) { } @Override public void onGuarantee(String permisson, int position) { } }); } }
手机端界面代码
package com.cdl.socket.activity; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.cdl.socket.R; import com.cdl.socket.client.MainParsener; import com.cdl.socket.config.SocketConfig; import com.cdl.socket.db.BindInfo; import com.cdl.socket.db.DbBindAdapter; import com.cdl.socket.db.DbManager; import com.cdl.socket.util.FileUrlUtil; import com.cdl.socket.util.SharedPerManager; import com.cdl.socket.view.MainView; import com.cdl.view.dialog.OridinryDialog; import com.com.view.customview.TopBarView; import com.lemonade.widgets.slidesidemenu.SlideSideMenuTransitionLayout; import com.util.NetWorkUtils; import com.uuzuche.lib_zxing.activity.CodeUtils; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class SocketClient extends Activity implements MainView, View.OnClickListener, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener { private Button btn_image_send; private MainParsener mainParsener; private TopBarView top_view_client; private SlideSideMenuTransitionLayout mSlideSideMenu; private ListView lv_da_info; private TextView tv_ip_local; DbBindAdapter adapter; private List<BindInfo> lists_bind = new ArrayList<>(); FileUrlUtil fileUrlUtil; OridinryDialog mOridinryDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_slide_side_menu_example); initView(); initMenu(); initListener(); } private void initListener() { top_view_client.setTopBarListener(new TopBarView.TopBarListener() { @Override public void leftClick() { mSlideSideMenu.toggle(); } @Override public void rightClick() { mainParsener.goToScan(); //检查相机权限并扫描二维码 } }); } private void initView() { mOridinryDialog = new OridinryDialog(SocketClient.this, SharedPerManager.getScreenWidth(), SharedPerManager.getScreenHeight()); mSlideSideMenu = (SlideSideMenuTransitionLayout) findViewById(R.id.slide_side_menu); top_view_client = (TopBarView) findViewById(R.id.top_view_client); btn_image_send = (Button) findViewById(R.id.btn_image_send); btn_image_send.setOnClickListener(this); tv_ip_local = (TextView) findViewById(R.id.tv_ip_local); mainParsener = new MainParsener(SocketClient.this, this); mainParsener.checkAppPermission(); //检查APP需要使用的权限 fileUrlUtil = new FileUrlUtil(SocketClient.this); } /*** * 初始化侧滑菜单 */ private void initMenu() { lv_da_info = (ListView) findViewById(R.id.lv_da_info); adapter = new DbBindAdapter(SocketClient.this, lists_bind); lv_da_info.setAdapter(adapter); lists_bind = DbManager.queryBindInfo(); adapter.setLists(lists_bind); lv_da_info.setOnItemClickListener(this); lv_da_info.setOnItemLongClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_image_send: mainParsener.checkSdcardPermission(getIpSend()); //检查SD卡权限 , break; } } @Override protected void onResume() { super.onResume(); tv_ip_local.setText("本机IP: " + NetWorkUtils.GetIpAddress(SocketClient.this)); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == SocketConfig.REQUEST_CODE) { if (null == data) { return; } dealErCodeMessage(resultCode, data); } else if (requestCode == SocketConfig.FILE_CHOOICE_BACK) { Log.w("fileBack", "======接受到文件==="); String path = ""; //文件选择器,选择文件返回的数据 Uri uri = data.getData(); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {//4.4以后 path = fileUrlUtil.getPath(uri); } else {//4.4以下下系统调用方法 path = fileUrlUtil.getRealPathFromURI(uri); } Log.w("fileBack", "======接受到文件===" + path); mainParsener.sendFileMessage(getIpSend(), path); } } /*** * 处理二维码相关的业务 * @param resultCode * @param data */ private void dealErCodeMessage(int resultCode, Intent data) { try { Bundle bundle = data.getExtras(); if (bundle == null) { showTaost("解析二维码失败"); return; } if (bundle.getInt(CodeUtils.RESULT_TYPE) == CodeUtils.RESULT_SUCCESS) { String result = bundle.getString(CodeUtils.RESULT_STRING); JSONObject jsonject = new JSONObject(result); String wifi_name = jsonject.getString("wifi_name"); String ip_address = jsonject.getString("ip_address"); String lineWifiName = NetWorkUtils.getConnectName(SocketClient.this); if (!lineWifiName.contains(wifi_name.trim())) { mOridinryDialog.show("请连接 <" + wifi_name + "> 这个WIFI,进行传输", "去联网", "取消"); mOridinryDialog.setOnDialogClickListener(new OridinryDialog.OridinryDialogClick() { @Override public void sure() { Intent wifiSettingsIntent = new Intent("android.settings.WIFI_SETTINGS"); startActivity(wifiSettingsIntent); } @Override public void noSure() { } }); return; } top_view_client.setTitleText(ip_address); DbManager.addBindInfo(ip_address); //增加IP到数据库 //扫描二维码后,刷新数据列表 lists_bind = DbManager.queryBindInfo(); adapter.setLists(lists_bind); showTaost("绑定设备成功"); } else if (bundle.getInt(CodeUtils.RESULT_TYPE) == CodeUtils.RESULT_FAILED) { showTaost("解析二维码失败"); } } catch (Exception e) { showTaost("解析二维码失败:" + e.toString()); } } //======================================================================================== public String getIpSend() { return top_view_client.getTitleText(); } @Override public void showTaost(String desc) { Toast.makeText(SocketClient.this, desc, Toast.LENGTH_LONG).show(); } @Override public void refreshDbInfo(boolean isSuccess) { if (isSuccess) { lists_bind = DbManager.queryBindInfo(); adapter.setLists(lists_bind); } } /*** * listView item点击事件 * @param parent * @param view * @param position * @param id */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String bindInfoString = lists_bind.get(position).getDevicdid(); top_view_client.setTitleText(bindInfoString); mSlideSideMenu.toggle(); showTaost("绑定设备成功"); } /*** * listView 长按事件 * @param parent * @param view * @param position * @param id * @return */ @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { String delInfo = lists_bind.get(position).getDevicdid(); mainParsener.delBindInfo(delInfo); return false; } @Override protected void onDestroy() { super.onDestroy(); if (mainParsener != null) { mainParsener.stopSendFile(); //停止发送文件 } } }