在Java ME設備上執行藍牙應用程序的首要步驟之一就是發現過程(discovery process)。簡而言之就是,發現過程就是帶有藍牙的設備互相找到彼此的過程,然後一起攜手找出它們各個可以支持的服務。下一步就是要學習如何在這些兩兩設備之間傳送數據。
在本篇技術小文章中,我將向你展示如何創建一個可以互相查找設備的一個MIDlet,然後讓用戶發送一個簡單的消息到其中一個被找到的設備中。我已經在Nokia N95的機器上測試並核實了這個MIDlet的工作了,通過啟用藍牙支持,它可以連接到一個運行Windows Vista的電腦上。
我把整個過程分成以下幾個步驟:
1. 開始發現過程。
2. 查詢在發現過程中找到的設備所支持的服務。
3. 使用支持服務的URL開始並處理一個OBEX數據交換。
以下各段將詳細說明這些步驟。在這些步驟中遵循代碼片段可以查閱這個MIDlet的整個源代碼。源代碼可以在最後的Resources下的壓縮文件中獲得。
第一步:開始發現過程
發現過程是用來告訴本地藍牙堆棧可以和在附近任何藍牙設備進行配對。在這個MIDlet中,這個堆棧可以通過你的設備提供者所提供的JSR 82來完成。這個發現過程通過發現在本地設備中的代理來開始的,如以下代碼所示:
// get the local discovery agent
agent = LocalDevice.getLocalDevice().getDiscoveryAgent();
// start the inquiry for general unlimited inquiry
agent.startInquiry(DiscoveryAgent.GIAC, this);
一旦發現代理啟動發現過程,它將在一個執行DiscoveryListener接口的類上調用各種調回方法。就我們而言,這是我們的MIDlet類。
具體來說,必須執行這個接口的四個方法,其中兩個是在發現階段我們所感興趣的:deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) 和 inquiryCompleted(int discType)。這兩個方法處理一個設備的發現並完成發現過程。在以下所展示的來自MIDlet的代碼中,一旦它們被發現或是當程序結束的時候,我們使用這些方法來添加我們的設備上的UI。
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
try {
// add the devices using the frIEndly names
listofDevices.append(btDevice.getFrIEndlyName(false), null);
// add to the devices hashtable
devices.put(new Long(listofDevices.size()), btDevice);
} catch(Exception ex) { handleError(ex); }
}
public void inquiryCompleted(int discType) {
// once the inquiry is completed, show the list of devices to the user
if(listofDevices.size() == 0) {
display.setCurrent(nothing, noteBox);
} else {
display.setCurrent(listofDevices);
}
}
第二步: 在已發現的設備上開始服務發現(service discovery)
由於本文的目的是讓數據從我們的MIDlet中傳輸到一個兼容的設備上,我們需要在已發現的設備上找到這些服務來實現這個目標。為了達到這個目的,我們需要在服務發現過程中定義正確的屬性和UUIDs。以下代碼將顯示如何來做這個:
agent.searchServices(
null,
new UUID[] {new UUID(0x1105L)}, // we want the OBEX PUSH Profile
device,
this);
正如你所猜到的,這些代碼使用我們以前用過的本地代理來查找設備。我們不是在一組特定的屬性之後,所以我們需要用null作為第一個參數,但是UUID必須是OBEX PUSH配置文件,因為這是傳輸數據的一個最開放式的方法。
我們講到DiscoveryListener接口有兩個其他的方法可以用來利用發現的服務。這兩個方法是servicesDiscovered(int transID, ServiceRecord[] servRecord) 和serviceSearchCompleted(int transID, int respCode)。正如名字所顯示的那樣,第一個方法是每當一個服務被發現時被調用,第二個方法當服務過程結束時被調用。
每當一個服務被發現的時候,我們需要找到每個設備上的特定的URL服務連接。這個URL連接將使OBEX連接用於我們的數據傳送,而且由藍牙硬件,設備地址組成。在以下的代碼中,這個URL連接取自於servicesDiscovered方法:
String connURL = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
通過這個URL連接,現在我們可以把傳輸數據的程序移動到已發現得設備上。
第三步:使用PBEX PUT傳送數據
在這個MIDlet中,我們將運行用戶輸入一些文本作為一個消息,然後用已發現的設備或是服務來傳送它們。為了做這個,我們需要在前一步驟中得到的URL連接(當然,消息數據是作為一個String的)。
// open a clIEnt session
ClientSession clIEntSession =
(ClIEntSession) Connector.open(connURL);
// connect using no headers
clIEntSession.connect(null);
if(rHeaders.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
// the connection could not be established
handleError(
new Exception("Remote clIEnt returned invalid response code: " +
rHeaders.getResponseCode()));
return;
}
// if we are here, then response code was ok
// create a new set of headers
HeaderSet headers = clIEntSession.createHeaderSet();
headers.setHeader(
HeaderSet.LENGTH,
new Long(noteBox.getString().length()));
headers.setHeader(HeaderSet.NAME, "myNote.txt");
headers.setHeader(HeaderSet.TYPE, "text/plain");
// create an Operation using the headers we have just created
Operation op = clIEntSession.put(headers);
// on this Operation, create the output stream
OutputStream out = op.openOutputStream();
// and send the note
out.write(noteBox.getString().getBytes());
為了發送該數據,clIEnt session被打開,而且建立一個空標題的連接。在這一點上,你的目標設備要求來自一個新設備的數據接收的確認。如果你以前從來沒有配對的設備,也可能要求你提供密鑰。
一旦連接建立,解釋數據目的地一些標題會被創建,而且一個新的操作通過這些標題也會被創建。這個操作是通過OutputStream來進行傳送數據的。
接收到的消息放在目標設備上的默認藍牙交換文件夾中。