问题
I am developing an app in which I need to transfer data in file between two devices.
I have seen tutorial regarding Bluetooth chat but can't figure out what stuff needed for file transfer. How can I do this?
回答1:
Today i had the same task & after spending couple of hours i'd achieved this. I'm posting the whole code so someone else can easily understand this. This is my Activity:
package com.aqua.bluetoothfiletransfer.indragni;
import java.io.File;
import java.util.List;
import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.aqua.bluetoothfiletransfer.R;
public class MainActivity extends AppCompatActivity {
private static final int DISCOVER_DURATION = 300;
private static final int REQUEST_BLU = 1;
String path;
private static final String[] INITIAL_PERMS = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS,
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION};
private static final int INITIAL_REQUEST = 1337;
private static final int REQUEST_WRITE_STORAGE = INITIAL_REQUEST + 4;
TextView textView_FileName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mainn);
textView_FileName = (TextView) findViewById(R.id.textView_FileName);
if (!canAccessLocation() || !canAccessCamera() || !canAccessWriteStorage() || !canAccessReadStorage() || !canAccessReadContacts() || !canAccessWriteContacts()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_WRITE_STORAGE:
if (canAccessWriteStorage()) {
//reload my activity with permission granted or use the features what required the permission
System.out.println("permission grantedddd");
} else {
Toast.makeText(this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
}
break;
}
}
public void sendViaBluetooth(View v) {
if (path == null) {
Toast.makeText(this, "Please select file first", Toast.LENGTH_SHORT).show();
return;
}
BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
if (btAdapter == null) {
Toast.makeText(this, "Bluetooth is not supported on this device", Toast.LENGTH_LONG).show();
} else {
enableBluetooth();
}
}
public void getFile(View v) {
Intent mediaIntent = new Intent(Intent.ACTION_GET_CONTENT);
mediaIntent.setType("*/*"); //set mime type as per requirement
startActivityForResult(mediaIntent, 1001);
}
public void enableBluetooth() {
Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoveryIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVER_DURATION);
startActivityForResult(discoveryIntent, REQUEST_BLU);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == DISCOVER_DURATION && requestCode == REQUEST_BLU) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("*/*");
File f = new File(path);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
PackageManager pm = getPackageManager();
List<ResolveInfo> appsList = pm.queryIntentActivities(intent, 0);
if (appsList.size() > 0) {
String packageName = null;
String className = null;
boolean found = false;
for (ResolveInfo info : appsList) {
packageName = info.activityInfo.packageName;
if (packageName.equals("com.android.bluetooth")) {
className = info.activityInfo.name;
found = true;
break;
}
}
if (!found) {
Toast.makeText(this, "Bluetooth havn't been found",
Toast.LENGTH_LONG).show();
} else {
intent.setClassName(packageName, className);
startActivity(intent);
}
}
} else if (requestCode == 1001
&& resultCode == Activity.RESULT_OK) {
Uri uriPath = data.getData();
Log.d("", "Video URI= " + uriPath);
path = getPath(this, uriPath);// "/mnt/sdcard/FileName.mp3"
System.out.println("pathhhh " + path);
textView_FileName.setText(path);
} else {
Toast.makeText(this, "Bluetooth is cancelled", Toast.LENGTH_LONG)
.show();
}
}
private boolean canAccessWriteStorage() {
return (hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE));
}
private boolean canAccessReadStorage() {
return (hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE));
}
private boolean canAccessReadContacts() {
return (hasPermission(Manifest.permission.READ_CONTACTS));
}
private boolean canAccessWriteContacts() {
return (hasPermission(Manifest.permission.WRITE_CONTACTS));
}
private boolean canAccessCamera() {
return (hasPermission(Manifest.permission.CAMERA));
}
private boolean canAccessLocation() {
return (hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
}
private boolean hasPermission(String perm) {
return (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this, perm));
}
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKatOrAbove = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKatOrAbove && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
This is my layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/textView_FileName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="Please select file"
android:textSize="18sp" />
<Button
android:id="@+id/button_GetFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="getFile"
android:text="Get file from device" />
<Button
android:id="@+id/button_SendFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="sendViaBluetooth"
android:text="Send via Bluetooth" />
</LinearLayout>
Last step is please declare all the permissions in manifest:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
That's it.
回答2:
File transfer is same like you send message. First you convert file to input stream and then transfer this to founded device.
回答3:
Something like this:
String addr = args[0];
log("Connecting over bluetooth to " + addr);
bs = null;
try {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(addr);
mBluetoothAdapter.cancelDiscovery();
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
bs = (BluetoothSocket) m.invoke(device, Integer.valueOf(1));
bs.connect();
} catch (Exception e) {
return false;
}
You need the MAC address of the device to which you are going to connect, and then just use the InputStream and OutputStream of bs
.
回答4:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("image/*");
String uri = "/mnt/sdcard/test.jpg";
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(uri)));
startActivity(intent);
Please set this code in your button and set uri to file path then press button your file will be transferred.
来源:https://stackoverflow.com/questions/4573761/bluetooth-file-transfer-in-android