How to transfer files without network in Android

How to transfer files without network in Android

A recent project required the implementation of a function for transferring files between Android phones without a network. I discovered a function called Wifi P2P (Wifi peer-to-peer), and finally implemented the function of transferring files over Wifi. Here I will also organize the code and share it with everyone.

Wifi P2P is a feature added in Android 4.0 and higher versions. Through Wifi P2P, you can directly exchange data with paired devices without connecting to the network. Compared with Bluetooth, Wifi P2P has faster search and transmission speeds and a longer transmission distance.

The effect achieved is as follows:

Generally speaking, the development steps are divided into the following points:

  • Declare relevant permissions (network and file read and write permissions) in AndroidManifest
  • Get WifiP2pManager, register related broadcasts to monitor the status changes of Wifi Direct
  • Designate a device as a server (to receive files), create a group and act as a group owner, listen for client connection requests on the designated port, and wait for clients to initiate connection requests and file transfer requests.
  • The client (used to send files) actively searches for nearby devices, joins the group created by the server, obtains the server's IP address, and initiates a file transfer request to it
  • Verify file integrity

1. Declare permissions

Wifi P2P technology does not access the network, but because it uses Java sockets, it needs to apply for network permissions. In addition, because it is to achieve file transfer, it also needs to apply for SD card read and write permissions.

  1. <uses-permission android: name = "android.permission.ACCESS_WIFI_STATE" />  
  2. <uses-permission android: name = "android.permission.CHANGE_WIFI_STATE" />  
  3. <uses-permission android: name = "android.permission.CHANGE_NETWORK_STATE" />  
  4. <uses-permission android: name = "android.permission.INTERNET" />  
  5. <uses-permission android: name = "android.permission.ACCESS_NETWORK_STATE" />  
  6. <uses-permission android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />  
  7. <uses-permission android: name = "android.permission.READ_EXTERNAL_STORAGE" />

2. Register Broadcast

The broadcasts related to Wifi P2P are as follows:

  • WIFI_P2P_STATE_CHANGED_ACTION (used to indicate whether Wifi P2P is available)
  • WIFI_P2P_PEERS_CHANGED_ACTION (The peer list has changed)
  • WIFI_P2P_CONNECTION_CHANGED_ACTION (Wifi P2P connection status has changed)
  • WIFI_P2P_THIS_DEVICE_CHANGED_ACTION (The device information of this device has changed)

When receiving these broadcasts, we need to go to WifiP2pManager (peer network manager) to make corresponding information requests. In addition, we also need to use the Channel object as a request parameter.

  1. mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);  
  2. mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);

When receiving the WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION broadcast, you can determine whether the current Wifi P2P is available

  1. int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {  
  2. mDirectActionListener.wifiP2pEnabled( true );  
  3. } else {  
  4. mDirectActionListener.wifiP2pEnabled( false );  
  5. }

When the WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION broadcast is received, it means that the list of available devices around the device has changed. You can get the list of available devices through the requestPeers method, and then you can select one of the devices to connect to.

  1. mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() { @Override  
  2. public void onPeersAvailable(WifiP2pDeviceList peers) {  
  3. mDirectActionListener.onPeersAvailable(peers.getDeviceList());  
  4. }  
  5. });

When WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION broadcast is received, it means that the connection status of Wifi P2P has changed, which may be connected to a device or disconnected from a device.

  1. NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {  
  2. mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() { @Override
  3.  
  4. public void onConnectionInfoAvailable(WifiP2pInfo info) {  
  5. mDirectActionListener.onConnectionInfoAvailable(info);  
  6. }  
  7. });  
  8. Log.e(TAG, "Connected to p2p device" );  
  9. } else {  
  10. mDirectActionListener.onDisconnection();  
  11. Log.e(TAG, "Disconnected from p2p device" );  
  12. }

If it is connected to a device, you can get the connection information through the requestConnectionInfo method

When receiving the WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION broadcast, you can get the device information after the device changes.

  1. (WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)

It can be seen that the Wifi P2P interface is highly asynchronous. So far, three system callback functions have been used, one for initializing WifiP2pManager and two for asynchronously requesting data in broadcasting. In order to simplify the operation, a custom callback function is used here, and the method meaning is consistent with the system callback function.

  1. public interface DirectActionListener extends WifiP2pManager.ChannelListener {  
  2. void wifiP2pEnabled(boolean enabled);  
  3. void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo);  
  4. void onDisconnection();  
  5. void onSelfDeviceAvailable(WifiP2pDevice wifiP2pDevice);  
  6. void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList);
  7. }

So, all the code used by the entire broadcast receiver is:

  1. /**
  2.  
  3. * Author: chenZY
  4.  
  5. * Time: 2018/2/9 17:53
  6.  
  7. * describe:
  8.  
  9. */  
  10. public class DirectBroadcastReceiver extends BroadcastReceiver {  
  11. private static final String TAG = "DirectBroadcastReceiver" ;  
  12. private WifiP2pManager mWifiP2pManager;  
  13. private WifiP2pManager.Channel mChannel;  
  14. private DirectActionListener mDirectActionListener;      
  15.  
  16. public DirectBroadcastReceiver(WifiP2pManager wifiP2pManager, WifiP2pManager.Channel channel, DirectActionListener directActionListener) {  
  17. mWifiP2pManager = wifiP2pManager;  
  18. mChannel = channel;  
  19. mDirectActionListener = directActionListener;  
  20. }
  21. public   static IntentFilter getIntentFilter() {  
  22. IntentFilter intentFilter = new IntentFilter();  
  23. intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);  
  24. intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);  
  25. intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);  
  26. intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
  27.  
  28. return intentFilter;  
  29. }
  30.  
  31. @Override  
  32. public void onReceive(Context context, Intent intent) {  
  33. Log.e(TAG, "Received broadcast: " + intent.getAction());
  34. if (!TextUtils.isEmpty(intent.getAction())) {
  35. switch (intent.getAction()) {
  36. // Used to indicate whether Wifi P2P is available
  37. case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION: {
  38. int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
  39. if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
  40. mDirectActionListener.wifiP2pEnabled( true );
  41. } else {
  42. mDirectActionListener.wifiP2pEnabled( false );
  43. List<WifiP2pDevice> wifiP2pDeviceList = new ArrayList<>();
  44. mDirectActionListener.onPeersAvailable(wifiP2pDeviceList);
  45. }
  46. break;
  47.   }
  48.  
  49. // The peer list has changed  
  50. case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION: {  
  51. mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
  52. @Override
  53.   public void onPeersAvailable(WifiP2pDeviceList peers) {
  54. mDirectActionListener.onPeersAvailable(peers.getDeviceList());
  55. }
  56. });
  57. break;
  58. }
  59.   // The Wifi P2P connection status has changed  
  60. case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION: {
  61. NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
  62. if (networkInfo.isConnected()) {
  63. mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {
  64. @Override
  65. public void onConnectionInfoAvailable(WifiP2pInfo info) {
  66. mDirectActionListener.onConnectionInfoAvailable(info);
  67. }
  68. });  
  69. Log.e(TAG, "Connected to p2p device" );  
  70. } else {  
  71. mDirectActionListener.onDisconnection();  
  72. Log.e(TAG, "Disconnected from p2p device" );  
  73. }  
  74. break;  
  75. }
  76.  
  77. //The device information of this device has changed  
  78. case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: {  
  79. mDirectActionListener.onSelfDeviceAvailable((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
  80. break;
  81. }
  82. }
  83. }
  84. }
  85. }

3. Create a group on the server

Assume that when device A searches for device B and connects to device B, the system will automatically create a group and randomly designate a device as the group owner. At this point, the IP address of the group owner is known to both devices (provided in the system callback function), but the client's IP address needs to be actively obtained through other methods. For example, after the device is successfully connected, the client can actively initiate a Socket connection request to the server, and the server listens for the client's connection request on the specified port. When the connection is successful, the server can obtain the client's IP address.

To simplify the operation, we will directly specify a device as the server (group owner), that is, directly specify a device to receive files.

Therefore, the server needs to actively create a group and wait for the client to connect.

  1. wifiP2pManager.createGroup(channel, new WifiP2pManager.ActionListener() {  
  2. @Override
  3. public void onSuccess() {
  4. Log.e(TAG, "createGroup onSuccess" );
  5. dismissLoadingDialog();
  6. showToast( "onSuccess" );
  7. }
  8.  
  9. @Override
  10. public void onFailure( int reason) {
  11. Log.e(TAG, "createGroup onFailure: " + reason);
  12. dismissLoadingDialog();
  13. showToast( "onFailure" );
  14. }
  15. });

Here, IntentService is used to listen to the client's Socket connection request in the background and transfer files through input and output streams. The code here is relatively simple. It just blocks the specified port to listen to the client's connection request, obtains the file information model FileTransfer to be transferred, and then performs the actual data transfer.

  1. @Override  
  2. protected void onHandleIntent(Intent intent) {
  3. clean();
  4. File file = null ;
  5. try {  
  6. serverSocket = new ServerSocket();  
  7. serverSocket.setReuseAddress( true );  
  8. serverSocket.bind(new InetSocketAddress(PORT));  
  9. Socket client = serverSocket.accept();  
  10. Log.e(TAG, "Client IP address: " + client.getInetAddress().getHostAddress());  
  11. inputStream = client.getInputStream();  
  12. objectInputStream = new ObjectInputStream(inputStream);  
  13. FileTransfer fileTransfer = (FileTransfer) objectInputStream.readObject();  
  14. Log.e(TAG, "File to be received: " + fileTransfer);  
  15. String name = new File(fileTransfer.getFilePath()).getName();
  16.  
  17. //Store the file in the specified location  
  18. file = new File(Environment.getExternalStorageDirectory() + "/" + name );  
  19. fileOutputStream = new FileOutputStream(file);
  20. byte buf[] = new byte[512];
  21. int len;
  22. long total = 0;
  23. int progress;
  24. while ((len = inputStream. read (buf)) != -1) {
  25. fileOutputStream.write(buf, 0, len);
  26. total += len;
  27. progress = ( int ) ((total * 100) / fileTransfer.getFileLength());
  28. Log.e(TAG, "File receiving progress: " + progress);
  29. if (progressChangListener != null ) {
  30. progressChangListener.onProgressChanged(fileTransfer, progress);
  31. }
  32.   }
  33. serverSocket.close () ;
  34. inputStream.close ();
  35. objectInputStream. close ();  
  36. fileOutputStream. close ();  
  37. serverSocket = null ;  
  38. inputStream = null ;  
  39. objectInputStream = null ;  
  40. fileOutputStream = null ;  
  41. Log.e(TAG, "File received successfully, the MD5 code of the file is: " + Md5Util.getMd5(file));  
  42. } catch (Exception e) {  
  43. Log.e(TAG, "File receiving Exception: " + e.getMessage());  
  44. finally  
  45. clean();
  46.   if (progressChangListener != null ) {  
  47. progressChangListener.onTransferFinished(file);  
  48. }
  49. //Start the service again and wait for the next client connection
  50. startService(new Intent(this, WifiServerService.class));
  51. }  
  52. }

Because the client may initiate connection requests multiple times, when the file transfer is completed here (regardless of success or failure), you need to restart the Service to make the service block again and wait for the client's connection request.

FileTransfer contains three fields. The MD5 code value is used to verify the integrity of the file, and fileLength is used to calculate the transfer progress of the file.

  1. public class FileTransfer implements Serializable {
  2. //File path
  3. private String filePath;  
  4. //File size
  5. private long fileLength;
  6. //MD5 code  
  7. private String md5;  
  8. ···
  9. }

In order to publish the file transfer progress to the external interface, in addition to starting the Service, the interface also needs to bind the Service. Here, an interface for updating the file transfer status is needed.

  1. public interface OnProgressChangListener {  
  2. //When the transfer progress changes  
  3. void onProgressChanged(FileTransfer fileTransfer, int progress);
  4. //When the transfer is finished
  5. void onTransferFinished(File file);
  6. }

Therefore, you need to pass progressChangListener as a parameter to WifiServerService and update the progress dialog when the progress changes.

  1. private WifiServerService.OnProgressChangListener progressChangListener = new WifiServerService.OnProgressChangListener() {
  2. @Override
  3. public void onProgressChanged(final FileTransfer fileTransfer, final int progress) {
  4. runOnUiThread(new Runnable() {
  5. @Override
  6. public void run() {
  7.   progressDialog.setMessage( "File name: " + new File(fileTransfer.getFilePath()).getName());
  8. progressDialog.setProgress(progress);
  9. progressDialog.show();
  10. }
  11. });
  12.   }
  13.  
  14. @Override  
  15. public void onTransferFinished(final File file) {  
  16. runOnUiThread(new Runnable() {
  17. @Override
  18. public void run() {
  19. progressDialog.cancel();
  20. if (file != null &amp;&amp; file.exists()) {
  21. openFile(file.getPath());
  22. }
  23. }
  24. });
  25. }
  26. };

4. The client joins the group and initiates a file transfer request

The file sending interface SendFileActivity needs to implement the DirectActionListener interface

First, you need to register P2P broadcast to obtain surrounding device information and connection status.

  1. @Override  
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);  
  4. setContentView(R.layout.activity_send_file);  
  5. initView();  
  6. mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);  
  7. mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);  
  8. broadcastReceiver = new DirectBroadcastReceiver(mWifiP2pManager, mChannel, this);  
  9. registerReceiver(broadcastReceiver, DirectBroadcastReceiver.getIntentFilter());  
  10. }

Use the discoverPeers method to search for peripheral devices. The callback function is used to notify whether the method is successfully called.

  1. mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { @Override  
  2. public void onSuccess() {  
  3. showToast( "Success" );  
  4. }
  5.  
  6. @Override  
  7. public void onFailure( int reasonCode) {  
  8. showToast( "Failure" );  
  9. loadingDialog.cancel();
  10. }  
  11. });

When the search is finished, the system will trigger the WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION broadcast. At this time, you can call the requestPeers method to obtain the device list information. Here, RecyclerView is used to display the list, and the list is refreshed in the onPeersAvailable method.

  1. mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {  
  2. @Override  
  3. public void onPeersAvailable(WifiP2pDeviceList peers) {  
  4. mDirectActionListener.onPeersAvailable(peers.getDeviceList());  
  5. }
  6. });
  7.  
  8. @Override  
  9. public void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList) {  
  10. Log.e(TAG, "onPeersAvailable :" + wifiP2pDeviceList. size ());
  11. this.wifiP2pDeviceList.clear();
  12. this.wifiP2pDeviceList.addAll(wifiP2pDeviceList);  
  13. deviceAdapter.notifyDataSetChanged();
  14. loadingDialog.cancel();
  15. }

After that, select the group owner (server) device through the click event and request to connect to it through the connect method

  1. private void connect () {  
  2. WifiP2pConfig config = new WifiP2pConfig();  
  3. if (config.deviceAddress != null &amp;&amp; mWifiP2pDevice != null ) {  
  4. config.deviceAddress = mWifiP2pDevice.deviceAddress;  
  5. config.wps.setup = WpsInfo.PBC;  
  6. showLoadingDialog( "Connecting " + mWifiP2pDevice.deviceName);  
  7. mWifiP2pManager.connect (mChannel, config, new WifiP2pManager.ActionListener() {
  8.  
  9. @Override  
  10. public void onSuccess() {  
  11. Log.e(TAG, "connect onSuccess" );  
  12. }
  13.  
  14. @Override  
  15. public void onFailure( int reason) {
  16. showToast( "Connection failed " + reason);  
  17. dismissLoadingDialog();
  18. }  
  19. });  
  20. }
  21.   }

Here, the connection result cannot be determined by the function function. You need to rely on the WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION method issued by the system to obtain the connection result. Here, you can obtain the group connection information through requestConnectionInfo. The information is finally passed through the onConnectionInfoAvailable method. Here you can determine whether the current device is the group owner and obtain the group IP address.

  1. @Override  
  2. public void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo) {  
  3. dismissLoadingDialog();  
  4. wifiP2pDeviceList.clear();  
  5. deviceAdapter.notifyDataSetChanged();  
  6. btn_disconnect.setEnabled( true );  
  7. btn_chooseFile.setEnabled( true );  
  8. Log.e(TAG, "onConnectionInfoAvailable" );  
  9. Log.e(TAG, "onConnectionInfoAvailable groupFormed: " + wifiP2pInfo.groupFormed);  
  10. Log.e(TAG, "onConnectionInfoAvailable isGroupOwner: " + wifiP2pInfo.isGroupOwner);  
  11. Log.e(TAG, "onConnectionInfoAvailable getHostAddress: " + wifiP2pInfo.groupOwnerAddress.getHostAddress());  
  12. StringBuilder stringBuilder = new StringBuilder();
  13.  
  14. if (mWifiP2pDevice != null ) {  
  15. stringBuilder.append( "Connected device name: " );  
  16. stringBuilder.append(mWifiP2pDevice.deviceName);  
  17. stringBuilder.append( "\n" );  
  18. stringBuilder.append( "Address of the connected device:" );  
  19. stringBuilder.append(mWifiP2pDevice.deviceAddress);  
  20. }
  21.  
  22. stringBuilder.append( "\n" );  
  23. stringBuilder.append( "Is this the group owner: " );  
  24. stringBuilder.append(wifiP2pInfo.isGroupOwner ? "Is group owner" : "Not group owner" );  
  25. stringBuilder.append( "\n" );  
  26. stringBuilder.append( "Group owner's IP address: " );  
  27. stringBuilder.append(wifiP2pInfo.groupOwnerAddress.getHostAddress());  
  28. tv_status.setText(stringBuilder);
  29.   if (wifiP2pInfo.groupFormed &amp;&amp; !wifiP2pInfo.isGroupOwner) {
  30. this.wifiP2pInfo = wifiP2pInfo;  
  31. }  
  32. }

At this point, the server and client have been connected through Wifi P2P, and the client has obtained the IP address of the server. After selecting the file to be sent, it can actively initiate a connection request to the server.

Method to initiate file selection

  1. Intent intent = new Intent(Intent.ACTION_GET_CONTENT);  
  2. intent.setType( "*/*" );
  3. intent.addCategory(Intent.CATEGORY_OPENABLE);  
  4. startActivityForResult(intent, 1);

Get the actual path of the selected file

  1. @Override  
  2. protected void onActivityResult( int requestCode, int resultCode, Intent data) {  
  3. super.onActivityResult(requestCode, resultCode, data);  
  4. if (requestCode == 1) {
  5. if (resultCode == RESULT_OK) {
  6. Uri uri = data.getData();
  7.   if (uri != null ) {  
  8. String path = getPath(this, uri);
  9. if (path != null ) {
  10. File file = new File(path);
  11. if (file.exists() &amp;&amp; wifiP2pInfo != null ) {
  12. FileTransfer fileTransfer = new FileTransfer(file.getPath(), file.length());
  13. Log.e(TAG, "File to be sent: " + fileTransfer);
  14. new WifiClientTask(this, fileTransfer). execute (wifiP2pInfo.groupOwnerAddress.getHostAddress());
  15. }
  16. }  
  17. }  
  18. }  
  19. }  
  20. }                          
  21.  
  22. private String getPath(Context context, Uri uri) {  
  23. if ( "content" .equalsIgnoreCase(uri.getScheme())) {  
  24. Cursor   cursor = context.getContentResolver().query(uri, new String[]{ "_data" }, null , null , null );
  25. if ( cursor != null ) {
  26. if ( cursor .moveToFirst()) {
  27. String data = cursor .getString( cursor .getColumnIndex( "_data" ));
  28. cursor.close ( ) ;
  29. return data;  
  30. }  
  31. }  
  32. } else if ( "file" .equalsIgnoreCase(uri.getScheme())) {
  33. return uri.getPath();
  34. }
  35.   return   null ;  
  36. }

The file sending operation is processed in AsyncTask, and the server IP address is passed in as a parameter. Before the file is officially sent, the information model FileTransfer containing the file information (file name, file size, file MD5 code) is sent first, and the progress is updated during the file sending process.

  1. /**  
  2. * Author: Ye Ying Shi Ye  
  3. * Time: 2018/2/15 8:51  
  4. * Description: The client sends a file  
  5. */
  6.  
  7. public class WifiClientTask extends AsyncTask<String, Integer , Boolean> {
  8. private ProgressDialog progressDialog;
  9. private FileTransfer fileTransfer;
  10. private static final int PORT = 4786;
  11. private static final String TAG = "WifiClientTask" ;      
  12.  
  13. public WifiClientTask(Context context, FileTransfer fileTransfer) {
  14. this.fileTransfer = fileTransfer;  
  15. progressDialog = new ProgressDialog(context);  
  16. progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);  
  17. progressDialog.setCancelable( false );  
  18. progressDialog.setCanceledOnTouchOutside( false );  
  19. progressDialog.setTitle( "Sending file" );  
  20. progressDialog.setMax(100);  
  21. }
  22.  
  23. @Override  
  24. protected void onPreExecute() {  
  25. progressDialog.show();  
  26. }
  27.  
  28. @Override
  29.   protected Boolean doInBackground(String... strings) {  
  30. fileTransfer.setMd5(Md5Util.getMd5(new File(fileTransfer.getFilePath())));  
  31. Log.e(TAG, "The MD5 code value of the file is: " + fileTransfer.getMd5());  
  32. Socket socket = null ;  
  33. OutputStream outputStream = null ;  
  34. ObjectOutputStream objectOutputStream = null ;  
  35. InputStream inputStream = null ;
  36. try {
  37. socket = new Socket();  
  38. socket.bind( null );  
  39. socket.connect ((new InetSocketAddress(strings[0], PORT)), 10000);  
  40. outputStream = socket.getOutputStream();  
  41. objectOutputStream = new ObjectOutputStream(outputStream);  
  42. objectOutputStream.writeObject(fileTransfer);  
  43. inputStream = new FileInputStream(new File(fileTransfer.getFilePath()));
  44. long fileSize = fileTransfer.getFileLength();
  45.   long total = 0;  
  46. byte buf[] = new byte[512];
  47.  
  48. int len;  
  49. while ((len = inputStream. read (buf)) != -1) {  
  50. outputStream.write(buf, 0, len);  
  51. total += len;
  52.   int progress = ( int ) ((total * 100) / fileSize);
  53. publishProgress(progress);  
  54. Log.e(TAG, "File sending progress: " + progress);  
  55. }  
  56. outputStream. close ();  
  57. objectOutputStream. close ();  
  58. inputStream.close ();  
  59. socket.close () ;  
  60. outputStream = null ;  
  61. objectOutputStream = null ;  
  62. inputStream = null ;  
  63. socket = null ;  
  64. Log.e(TAG, "File sent successfully" );
  65.  
  66. return   true ;
  67.  
  68. } catch (Exception e) {  
  69. Log.e(TAG, "File sending exception Exception: " + e.getMessage());  
  70. finally
  71. if (outputStream != null ) {
  72. try {
  73. outputStream. close ();  
  74. } catch (IOException e) {  
  75. e.printStackTrace();
  76. }
  77. }  
  78. if (objectOutputStream != null ) {
  79. try {
  80.  
  81. objectOutputStream. close ();  
  82. } catch (IOException e) {  
  83. e.printStackTrace();  
  84. }  
  85. }
  86.  
  87. if (inputStream != null ) {
  88. try {  
  89. inputStream.close ();  
  90. } catch (IOException e) {  
  91. e.printStackTrace();  
  92. }
  93. }  
  94. if (socket != null ) {
  95. try {
  96. socket.close () ;
  97. } catch (Exception e) {
  98. e.printStackTrace();
  99. }  
  100. }  
  101. }  
  102. return   false ;  
  103. }  
  104.  
  105. @Override  
  106. protected void onProgressUpdate( Integer ... values ​​) {  
  107. progressDialog.setProgress( values ​​[0]);  
  108. }
  109.  
  110. @Override  
  111. protected void onPostExecute(Boolean aBoolean) {  
  112. progressDialog.cancel();  
  113. Log.e(TAG, "onPostExecute: " + aBoolean);  
  114. }  
  115. }

5. Verify file integrity

The integrity of the transferred file is mainly ensured by calculating the MD5 code value of the file. Before sending the file, the calculation is performed in the doInBackground method of WifiClientTask, and the MD5 code value is assigned to the FileTransfer model. It is calculated by the following method

  1. /**  
  2. * Author: Ye Ying Shi Ye  
  3. * Time: 2018/2/14 21:16  
  4. * describe:  
  5. */  
  6. public class Md5Util {  
  7. public   static String getMd5(File file) {  
  8. InputStream inputStream = null ;
  9. byte[] buffer = new byte[2048];
  10. int numRead;
  11. MessageDigest md5;
  12. try {  
  13. inputStream = new FileInputStream(file);  
  14. md5 = MessageDigest.getInstance( "MD5" );
  15. while ((numRead = inputStream. read (buffer)) > 0) {
  16. md5.update (buffer, 0, numRead);
  17. }
  18. inputStream.close ();  
  19. inputStream = null ;
  20. return md5ToString(md5.digest());
  21. } catch (Exception e) {
  22. return   null ;
  23. finally
  24. if (inputStream != null ) {
  25. try {
  26. inputStream.close ();
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
  32. }
  33.  
  34. private static String md5ToString(byte[] md5Bytes) {  
  35. StringBuilder hexValue = new StringBuilder();
  36. for (byte b : md5Bytes) {
  37. int val = (( int ) b) &amp; 0xff;
  38. if (val < 16) {
  39. hexValue.append( "0" );
  40. }  
  41. hexValue.append( Integer .toHexString(val));  
  42. }  
  43. return hexValue.toString();  
  44. }  
  45. }

Because the client will send FileTransfer to the server, the server can recalculate the MD5 code value of the file after the file transfer is completed and compare it to determine whether the file is complete.

Code address: https://github.com/leavesC/WifiP2P

<<:  Android P preview version hands-on experience: never get lost again

>>:  To protect the security of WeChat and Alipay, use these five functions of your mobile phone with caution!

Recommend

Create vitality, ZIVOO seizes the commanding heights of smart home fashion

Home electronic products always give people the i...

Advanced Software Test-System Architect Elite Class 2022 5th

Course Catalog: ├──1–Understanding and cognition ...

Are the hazards of sitting for a long time so serious?

Everyone knows that sitting for a long time is ba...

Julien "Tengame" RSD video tutorial

Julien's "Tengame" tutorial introdu...

How to assess activity risks and improve activity strategies and gameplay?

Once the back-end strategy and front-end gameplay...

The most comprehensive case analysis of event planning and operation strategies

Today I’d like to talk to you about how to run a ...

Why don’t hotels check rooms nowadays? What should I do if something is lost?

In recent years, many people have found that chec...

Xiaohongshu’s operational minefields are explained in one article!

In December last year, Xiaohongshu announced that...