我需要发送文件到计算机,而不是另一个Android应用程序。我已经看过蓝牙api,但它只允许连接作为客户端服务器。在我的情况下,我不知道UUId会在电脑上。我需要看obex。我以前没有用过它。所以任何帮助都是有益的。如何在android上以编程方式发送使用蓝牙的文件?
回答
试试这个。 我可以使用此代码发送文件。
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, "file:///sdcard/refresh.txt");
values.put(BluetoothShare.DESTINATION, deviceAddress);
values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
getContentResolver().insert(BluetoothShare.CONTENT_URI, values);
BluetoothShare.java
import android.provider.BaseColumns;
import android.net.Uri;
/**
* Exposes constants used to interact with the Bluetooth Share manager's content
* provider.
*/
public final class BluetoothShare implements BaseColumns {
private BluetoothShare() {
}
/**
* The permission to access the Bluetooth Share Manager
*/
public static final String PERMISSION_ACCESS = "android.permission.ACCESS_BLUETOOTH_SHARE";
/**
* The content:// URI for the data table in the provider
*/
public static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.opp/btopp");
/**
* Broadcast Action: this is sent by the Bluetooth Share component to
* transfer complete. The request detail could be retrieved by app * as _ID
* is specified in the intent's data.
*/
public static final String TRANSFER_COMPLETED_ACTION = "android.btopp.intent.action.TRANSFER_COMPLETE";
/**
* This is sent by the Bluetooth Share component to indicate there is an
* incoming file need user to confirm.
*/
public static final String INCOMING_FILE_CONFIRMATION_REQUEST_ACTION = "android.btopp.intent.action.INCOMING_FILE_NOTIFICATION";
/**
* This is sent by the Bluetooth Share component to indicate there is an
* incoming file request timeout and need update UI.
*/
public static final String USER_CONFIRMATION_TIMEOUT_ACTION = "android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT";
/**
* The name of the column containing the URI of the file being
* sent/received.
*/
public static final String URI = "uri";
/**
* The name of the column containing the filename that the incoming file
* request recommends. When possible, the Bluetooth Share manager will
* attempt to use this filename, or a variation, as the actual name for the
* file.
*/
public static final String FILENAME_HINT = "hint";
/**
* The name of the column containing the filename where the shared file was
* actually stored.
*/
public static final String _DATA = "_data";
/**
* The name of the column containing the MIME type of the shared file.
*/
public static final String MIMETYPE = "mimetype";
/**
* The name of the column containing the direction (Inbound/Outbound) of the
* transfer. See the DIRECTION_* constants for a list of legal values.
*/
public static final String DIRECTION = "direction";
/**
* The name of the column containing Bluetooth Device Address that the
* transfer is associated with.
*/
public static final String DESTINATION = "destination";
/**
* The name of the column containing the flags that controls whether the
* transfer is displayed by the UI. See the VISIBILITY_* constants for a
* list of legal values.
*/
public static final String VISIBILITY = "visibility";
/**
* The name of the column containing the current user confirmation state of
* the transfer. Applications can write to this to confirm the transfer. the
* USER_CONFIRMATION_* constants for a list of legal values.
*/
public static final String USER_CONFIRMATION = "confirm";
/**
* The name of the column containing the current status of the transfer.
* Applications can read this to follow the progress of each download. See
* the STATUS_* constants for a list of legal values.
*/
public static final String STATUS = "status";
/**
* The name of the column containing the total size of the file being
* transferred.
*/
public static final String TOTAL_BYTES = "total_bytes";
/**
* The name of the column containing the size of the part of the file that
* has been transferred so far.
*/
public static final String CURRENT_BYTES = "current_bytes";
/**
* The name of the column containing the timestamp when the transfer is
* initialized.
*/
public static final String TIMESTAMP = "timestamp";
/**
* This transfer is outbound, e.g. share file to other device.
*/
public static final int DIRECTION_OUTBOUND = 0;
/**
* This transfer is inbound, e.g. receive file from other device.
*/
public static final int DIRECTION_INBOUND = 1;
/**
* This transfer is waiting for user confirmation.
*/
public static final int USER_CONFIRMATION_PENDING = 0;
/**
* This transfer is confirmed by user.
*/
public static final int USER_CONFIRMATION_CONFIRMED = 1;
/**
* This transfer is auto-confirmed per previous user confirmation.
*/
public static final int USER_CONFIRMATION_AUTO_CONFIRMED = 2;
/**
* This transfer is denied by user.
*/
public static final int USER_CONFIRMATION_DENIED = 3;
/**
* This transfer is timeout before user action.
*/
public static final int USER_CONFIRMATION_TIMEOUT = 4;
/**
* This transfer is visible and shows in the notifications while in progress
* and after completion.
*/
public static final int VISIBILITY_VISIBLE = 0;
/**
* This transfer doesn't show in the notifications.
*/
public static final int VISIBILITY_HIDDEN = 1;
/**
* Returns whether the status is informational (i.e. 1xx).
*/
public static boolean isStatusInformational(int status) {
return (status >= 100 && status < 200);
}
/**
* Returns whether the transfer is suspended. (i.e. whether the transfer
* won't complete without some action from outside the transfer manager).
*/
public static boolean isStatusSuspended(int status) {
return (status == STATUS_PENDING);
}
/**
* Returns whether the status is a success (i.e. 2xx).
*/
public static boolean isStatusSuccess(int status) {
return (status >= 200 && status < 300);
}
/**
* Returns whether the status is an error (i.e. 4xx or 5xx).
*/
public static boolean isStatusError(int status) {
return (status >= 400 && status < 600);
}
/**
* Returns whether the status is a client error (i.e. 4xx).
*/
public static boolean isStatusClientError(int status) {
return (status >= 400 && status < 500);
}
/**
* Returns whether the status is a server error (i.e. 5xx).
*/
public static boolean isStatusServerError(int status) {
return (status >= 500 && status < 600);
}
/**
* Returns whether the transfer has completed (either with success or
* error).
*/
public static boolean isStatusCompleted(int status) {
return (status >= 200 && status < 300) || (status >= 400 && status < 600);
}
/**
* This transfer hasn't stated yet
*/
public static final int STATUS_PENDING = 190;
/**
* This transfer has started
*/
public static final int STATUS_RUNNING = 192;
/**
* This transfer has successfully completed. Warning: there might be other
* status values that indicate success in the future. Use isSucccess() to
* capture the entire category.
*/
public static final int STATUS_SUCCESS = 200;
/**
* This request couldn't be parsed. This is also used when processing
* requests with unknown/unsupported URI schemes.
*/
public static final int STATUS_BAD_REQUEST = 400;
/**
* This transfer is forbidden by target device.
*/
public static final int STATUS_FORBIDDEN = 403;
/**
* This transfer can't be performed because the content cannot be handled.
*/
public static final int STATUS_NOT_ACCEPTABLE = 406;
/**
* This transfer cannot be performed because the length cannot be determined
* accurately. This is the code for the HTTP error "Length Required", which
* is typically used when making requests that require a content length but
* don't have one, and it is also used in the client when a response is
* received whose length cannot be determined accurately (therefore making
* it impossible to know when a transfer completes).
*/
public static final int STATUS_LENGTH_REQUIRED = 411;
/**
* This transfer was interrupted and cannot be resumed. This is the code for
* the OBEX error "Precondition Failed", and it is also used in situations
* where the client doesn't have an ETag at all.
*/
public static final int STATUS_PRECONDITION_FAILED = 412;
/**
* This transfer was canceled
*/
public static final int STATUS_CANCELED = 490;
/**
* This transfer has completed with an error. Warning: there will be other
* status values that indicate errors in the future. Use isStatusError() to
* capture the entire category.
*/
public static final int STATUS_UNKNOWN_ERROR = 491;
/**
* This transfer couldn't be completed because of a storage issue.
* Typically, that's because the file system is missing or full.
*/
public static final int STATUS_FILE_ERROR = 492;
/**
* This transfer couldn't be completed because of no sdcard.
*/
public static final int STATUS_ERROR_NO_SDCARD = 493;
/**
* This transfer couldn't be completed because of sdcard full.
*/
public static final int STATUS_ERROR_SDCARD_FULL = 494;
/**
* This transfer couldn't be completed because of an unspecified un-handled
* OBEX code.
*/
public static final int STATUS_UNHANDLED_OBEX_CODE = 495;
/**
* This transfer couldn't be completed because of an error receiving or
* processing data at the OBEX level.
*/
public static final int STATUS_OBEX_DATA_ERROR = 496;
/**
* This transfer couldn't be completed because of an error when establishing
* connection.
*/
public static final int STATUS_CONNECTION_ERROR = 497;
}
冰淇淋三明治的代码这个代码不工作,所以你必须使用此代码
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Intent sharingIntent = new Intent(
android.content.Intent.ACTION_SEND);
sharingIntent.setType("image/jpeg");
sharingIntent
.setComponent(new ComponentName(
"com.android.bluetooth",
"com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(sharingIntent);
} else {
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, uri.toString());
Toast.makeText(getBaseContext(), "URi : " + uri,
Toast.LENGTH_LONG).show();
values.put(BluetoothShare.DESTINATION, deviceAddress);
values.put(BluetoothShare.DIRECTION,
BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
getContentResolver().insert(BluetoothShare.CONTENT_URI,
values);
}
可以使用OBEX库。看起来android没有提供obex库,但我解决了这个问题,并且解决方案发布了here。
进一步解释(请从开始这里阅读如果你很忙)
- 我试图创建一个Android手机遥控器(以及类似Telnet服务器的东西),这有助于控制用我的旧功能手机远程拨打电话。
主要内容:蓝牙FTP客户端
我的第一个计划是使应用程序检查我的功能手机的目录中的文件列表。
但我不知道如何连接到我的功能手机的FTP服务器。
我搜索了很多关于如何通过蓝牙连接到FTP服务器,但我只能发现Bluetoorh FTP服务器使用
OBEX Protocol
。我在一个SO线程中找到了一个有用的资料(PDF文件),并研究了OBEX连接请求,放置和获取操作。
所以我最后写了一些代码,试图连接到
Bluetooth FTP
服务器。我想给你看,但我失去了它:(代码就像直接写字节序列到输出流我也很难找出UUID使得应用程序连接为FTP客户端。不过,我尝试使用下面的代码的每一UUID的检索。
String parcels=""; ParcelUuid[] uuids=mBtDevice.getUuids(); int i=0; for (ParcelUuid p:uuids) { parcels += "UUID UUID" + new Integer(i).toString() + "=UUID.fromString((\"" + p.getUuid().toString() + "\"));\n\n"; ++i; }
似乎没有什么带我到我想要的答案,所以我一派越来越发现我不但要我用UUID 00001106-0000- 1000-8000-00805f9b34fb连接到OBEX FTP服务器,但也推迟我发送目标标题**与UUID ** F9EC7BC4-953C-11D2-984E -525400DC9E09当发送
OBEX connect
请求。 下面的代码显示了如何作为客户端连接到蓝牙FTP服务器。try { mBtSocket = mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(" 00001106-0000-1000-8000-00805f9b34fb")); } catch (Exception e) { //e.printStackTrace(); } Thread thread=new Thread(new Runnable() { public void run() { UUID uuid=UUID.fromString("F9EC7BC4-953C-11D2-984E-525400DC9E09"); ByteBuffer bb = ByteBuffer.wrap(new byte[16]); bb.putLong(uuid.getMostSignificantBits()); bb.putLong(uuid.getLeastSignificantBits()); byte [] bytes=bb.array(); Operation putOperation=null; Operation getOperation=null; try { // connect the socket mBtSocket.connect(); //I will explain below mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket))); HeaderSet headerset = new HeaderSet(); headerset.setHeader(HeaderSet.TARGET, bytes); headerset = mSession.connect(headerset); if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) { mConnected = true; } else { mSession.disconnect(headerset); } ...
- 但是我不想等待一个小时将我的命令发送到我的android手机。 (如果我增加轮询频率,如每天民意调查方法都有这将是低效的。)
- 设置OBEX库 将
import javax.obex;
添加到您的源代码。 如果您的编译器不支持OBEX库,请从here下载源代码并添加到您的项目中。 - 实施
ObexTransport
当您使用它时,您应该提供一个在库中实现ObexTransport
的类。它定义了库应该如何发送数据(如RFCOMM,TCP等)。示例实现是here。这可能会导致一些运行时或编译错误,如there's no method
。但是,您可以通过将方法调用替换为像return 4096
而不是return mSocket.getMaxTransmitPacketSize();
这样的常量来取代部分修复方法,取代public int getMaxTransmitPacketSize()
的if
语句。或者您可以尝试使用反射来获得这些方法的运行时间。 - 获取
BluetoothSocket
使用mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(" 00001105-0000-1000-8000-00805f9b34fb"));
获取蓝牙插座并致电connect()
。 - 创建
ClientSession
创建ObexTransport
实施的实例,并创建一个新的ClientSession
,如mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket)));
。 将OBEX连接请求发送到您的计算机OPP收件箱服务。
HeaderSet headerset = new HeaderSet(); // headerset.setHeader(HeaderSet.COUNT,n); headerset = mSession.connect(null); if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) { mConnected = true; }
使用
ClientSession
发送OBEX放置请求。protected boolean Put(ClientSession session, byte[] bytes, String as, String type) { // TODO: Implement this method //byte [] bytes; String filename=as; boolean retry=true; int times=0; while (retry && times < 4) { Operation putOperation=null; OutputStream mOutput = null; //ClientSession mSession = null; //ArrayUtils.reverse(bytes); try { // Send a file with meta data to the server final HeaderSet hs = new HeaderSet(); hs.setHeader(HeaderSet.NAME, filename); hs.setHeader(HeaderSet.TYPE, type); hs.setHeader(HeaderSet.LENGTH, new Long((long)bytes.length)); Log.v(TAG,filename); //Log.v(TAG,type); Log.v(TAG,bytes.toString()); putOperation = session.put(hs); mOutput = putOperation.openOutputStream(); mOutput.write(bytes); mOutput.close(); putOperation.close(); } catch (Exception e) { Log.e(TAG, "put failed", e); retry = true; times++; continue; //e.printStackTrace(); } finally { try { if(mOutput!=null) mOutput.close(); if(putOperation!=null) putOperation.close(); } catch (Exception e) { Log.e(TAG, "put finally" , e); retry = true; times++; continue; } //updateStatus("[CLIENT] Connection Closed"); } retry = false; return true; } return false; }
最后,断开连接。
private void FinishBatch(ClientSession mSession) throws IOException { mSession.disconnect(null); try { Thread.sleep((long)500); } catch (InterruptedException e) {} mBtSocket.close(); }
然后这里是一个包装类。
import android.bluetooth.*; import android.util.*; import java.io.*; import java.util.*; import javax.obex.*; public class BluetoothOPPHelper { String address; BluetoothAdapter mBtadapter; BluetoothDevice device; ClientSession session; BluetoothSocket mBtSocket; protected final UUID OPPUUID=UUID.fromString(("00001105-0000-1000-8000-00805f9b34fb")); private String TAG="BluetoothOPPHelper"; public BluetoothOPPHelper(String address) { mBtadapter=BluetoothAdapter.getDefaultAdapter(); device=mBtadapter.getRemoteDevice(address); try { mBtSocket = device.createRfcommSocketToServiceRecord(OPPUUID); } catch (IOException e) { throw new RuntimeException(e); } } public ClientSession StartBatch(int n) { ClientSession mSession = null; // TODO: Implement this method boolean retry=true; int times=0; while (retry && times < 4) { //BluetoothConnector.BluetoothSocketWrapper bttmp=null; try { mBtSocket.connect(); //bttmp = (new BluetoothConnector(device,false,BluetoothAdapter.getDefaultAdapter(),Arrays.asList(new UUID[]{OPPUUID,OPPUUID, OPPUUID}))).connect();//*/ device.createInsecureRfcommSocketToServiceRecord(OPPUUID); /*if(mBtSocket.isConnected()) { mBtSocket.close(); }*/ } catch (Exception e) { Log.e(TAG, "opp fail sock " + e.getMessage()); retry = true; times++; continue; } try { //mBtSocket=bttmp.getUnderlyingSocket(); // mBtSocket.connect(); BluetoothObexTransport mTransport = null; mSession = new ClientSession((ObexTransport)(mTransport = new BluetoothObexTransport(mBtSocket))); HeaderSet headerset = new HeaderSet(); // headerset.setHeader(HeaderSet.COUNT,n); headerset = mSession.connect(null); if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) { boolean mConnected = true; } else { Log.e(TAG, "SEnd by OPP denied;"); mSession.disconnect(headerset); times++; continue; } } catch (Exception e) { Log.e(TAG, "opp failed;" , e); retry = true; times++; continue; //e.rintStackTrace(); } retry=false; } return mSession; } protected boolean Put(ClientSession session, byte[] bytes, String as, String type) { // TODO: Implement this method //byte [] bytes; String filename=as; boolean retry=true; int times=0; while (retry && times < 4) { Operation putOperation=null; OutputStream mOutput = null; //ClientSession mSession = null; //ArrayUtils.reverse(bytes); try { // Send a file with meta data to the server final HeaderSet hs = new HeaderSet(); hs.setHeader(HeaderSet.NAME, filename); hs.setHeader(HeaderSet.TYPE, type); hs.setHeader(HeaderSet.LENGTH, new Long((long)bytes.length)); Log.v(TAG,filename); //Log.v(TAG,type); Log.v(TAG,bytes.toString()); putOperation = session.put(hs); mOutput = putOperation.openOutputStream(); mOutput.write(bytes); mOutput.close(); putOperation.close(); } catch (Exception e) { Log.e(TAG, "put failed", e); retry = true; times++; continue; //e.printStackTrace(); } finally { try { if(mOutput!=null) mOutput.close(); if(putOperation!=null) putOperation.close(); } catch (Exception e) { Log.e(TAG, "put finally" , e); retry = true; times++; continue; } //updateStatus("[CLIENT] Connection Closed"); } retry = false; return true; } return false; } protected boolean Put(ClientSession s, OPPBatchInfo info) { return Put(s,info.data,info.as,info.type); } private void FinishBatch(ClientSession mSession) throws IOException { mSession.disconnect(null); try { Thread.sleep((long)500); } catch (InterruptedException e) {} mBtSocket.close(); } public boolean flush() throws IOException { if (sendQueue.isEmpty()) { return true; } try { Thread.sleep((long)2000); } catch (InterruptedException e) {} ClientSession session=StartBatch(sendQueue.size()); if (session == null) { return false; } while (!sendQueue.isEmpty()) { if (Put(session, sendQueue.remove()) == false) { Log.e(TAG, "Put failed"); } } FinishBatch(session); return true; } Queue<OPPBatchInfo> sendQueue; public boolean AddTransfer(String as,String mimetype,byte[] data) { return sendQueue.add(new OPPBatchInfo(as,mimetype,data)); } class OPPBatchInfo { String as; String type; byte[] data; public OPPBatchInfo(String as,String type,byte[] data) { this.as=as; this.data=data; this.type=type; } }
}
那你现在连接的FTP客户端,就可以使用OBEX操作来发送文件,请求文件,列出目录等
从这里开始阅读,如果你是忙碌的 主要内容:OBEX OPP
对于我之前提到的原因,我贪婪地寻找操纵OPEX文件的OPP的方法。
您可能希望通过蓝牙正常传输文件(不需要定义协议并为其构建新的桌面应用程序)到您的计算机上,对吧?然后发送到桌面Windows电脑本机运行的OBEX OPP收件箱服务是最佳解决方案。那么我们如何连接到OPP(Obex Object Push)收件箱服务?
您需要实现FTP通过OBEX。一旦您实现了标准协议和配置文件,您的Android FTP实现将与几乎任何蓝牙FTP服务器进行互操作。您还需要实施OPP以获得最大的互操作性。 OBEX协议并不是很难实现,规格也是免费的。
- 1. 以编程方式在Android中使用蓝牙发送多个文件
- 2. Android - 通过蓝牙以编程方式发送图像
- 3. Android蓝牙文件发送
- 4. Android以编程方式蓝牙配对
- 5. 使用蓝牙以编程方式传输数据Android Android
- 6. 如何以编程方式配对蓝牙设备在Android
- 7. 如何在android中以编程方式激活蓝牙
- 8. 是否可以在Android上以编程方式关闭蓝牙发现功能?
- 9. Android蓝牙发送文字
- 10. 以编程方式使用蓝牙连接两个Android设备
- 11. 以编程方式启用/禁用蓝牙配置文件
- 12. 如何以编程方式配对蓝牙设备Android
- 13. Android蓝牙发送文件问题
- 14. Android - 通过蓝牙发送文件
- 15. 如何以编程方式在Symbian上使用PyS60配对蓝牙设备?
- 16. 以编程方式打开蓝牙
- 17. 蓝牙文件发送
- 18. Android蓝牙推送文件
- 19. Android蓝牙编程:通过蓝牙将事件/数据从蓝牙耳机发送到Android手机。
- 20. 以编程方式发送邮件Android
- 21. 在iOS中以编程方式禁用蓝牙硬件?
- 22. 在android中使用蓝牙发送文件
- 23. Android上的蓝牙不发送消息
- 24. 如何检查蓝牙是否以编程方式启用?
- 25. 如何以编程方式在OS X中设置蓝牙可发现模式
- 26. 如何以编程方式在WM中“通过蓝牙连接”?
- 27. Android蓝牙编程
- 28. 如何以编程方式将蓝牙(RN4020)与Android应用程序连接?
- 29. 发送文件使用内置的蓝牙应用程序在Android中
- 30. 使用CoreBluetooth以编程方式启用/禁用蓝牙
我不认为android支持obex.you可以看到新的蓝牙api为3.0我认为它支持不安全的蓝牙conn – 2011-02-07 13:34:56
我需要达到相同的功能类似于照片应用程序中的分享选项。分享 - >蓝牙 - >选择设备并发送 – Saqib 2011-02-07 13:44:25
你有没有,你如何实现@Saqib – abh22ishek 2015-11-19 18:49:46