我需要發送文件到計算機,而不是另一個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