Android BLE開發之操作IOS ANCS

前言

之前寫過兩篇有關于ANCS的文章,最近一段時間老是有人問關于得到ANCS服務的問題,因為IOS ANCS不同于其他的Peripheral一樣對周邊所有的藍牙設備廣播自己,而是僅有連接上配對并連接上IOS設備的可見,我想這對于Android、IOS、嵌入式等的開發都是一樣的。

現在將以前寫的Android ble操作ANCS的demo修改了一下,并集中對于ANCS的相關問題進行說明。

發現ANCS

熟悉IOS的都知道,IOS設備上的藍牙是有很大限制的,只能連接手表、耳機等周邊設備,甚至同樣是IOS平臺的設備都不能進行互聯。但是BLE的出現給了我們使用藍牙技術進行通信的可能。

這里我們用到的是IOS系統提供的ANCS服務獲取IOS分發的通知,包括消息、來電、計劃等,但是這個服務對于我們是不可見的,他并不主動進行廣播,我們使用BLE scan 并不能掃描到ANCS這個服務。

** 那么是不是意味著我們就無法找到這個ANCS服務了呢? **
答案是否定的,經過調查我們發現ANCS是基于GATT做的封裝,也就是他是一個BLE的gatt server,只是對通信過程加入了自定義的協議,他跟其他的Ble service是同等的,比如常見的Heart Rate。因此我們考慮通過其他的service連接上這個GATT server,然后在獲取ANCS服務的思路。

how_to_find_ancs.png
發現設備

想要連接藍牙設備我們首先要知道他的設備地址,但是IOS設備的藍牙是不主動廣播的,但是我們知道IOS是支持BLE廣播的。

這里我們就可以借由這個功能讓我們得到IOS設備的目標地址,當然你可以自己實現一個簡單的APP去startLeAdvertisment,因為我并不會IOS開發所以這里借助了一個第三方APP(LightBlue)來虛擬一個peripherial,例如Heart Rate.

然后在我們的Android APP中進行掃描,就能掃描到這個名稱為Heart Rate的周邊設備。

@Override
public void onScanResult(int callbackType, ScanResult result) {
    Log.d(TAG, "onScanResult Device Address :" + result.getDevice());

    BluetoothDevice device = result.getDevice();

    if (device.getName() != null && device.getName().equals("Heart Rate")) {
         mTargetDevice = device;
    }
}
連接設備

使用我們上一步得到的BluetoothDevice對象或者設備地址鏈接到Gatt操作。
安卓代碼示例如下:

device.connectGatt(getApplicationContext(), false, mGattCallback);

并在連接回調中,獲得連接的狀態:

private class LocalBluetoothGattCallback extends BluetoothGattCallback {

   @Override
   public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
       if (newState == BluetoothProfile.STATE_CONNECTED) {
           Log.d(TAG, "connected");

           mConnectedGatt = gatt;
       }
       if (newState == BluetoothProfile.STATE_DISCONNECTED) {
           Log.d(TAG, "disconnected");
           mConnectedGatt = null;
       }
   }

}
發現ANCS

當連接上GATT后,我們就可以調用discover函數去發現所有的服務。

gatt.discoverServices();

然后在發現服務的回調中就可以根據UUID獲得ANCS服務。

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    if (status == BluetoothGatt.GATT_SUCCESS) {
        BluetoothGattService ancsService = gatt.getService(UUID.fromString(Constants.service_ancs));
        if (ancsService == null) {
            Log.d(TAG, "ANCS cannot find");
        } else {
            Log.d(TAG, "ANCS find");

            mANCSService = ancsService;
            mDataSourceChar = ancsService.getCharacteristic(UUID.fromString(Constants.characteristics_data_source));
            mPointControlChar = ancsService.getCharacteristic(UUID.fromString(Constants.characteristics_control_point));
            mNotificationSourceChar = ancsService.getCharacteristic(UUID.fromString(Constants.characteristics_notification_source));


        }
    }
}

獲得ANCS后,我們也可以通過UUID獲得ANCS的三個characteristic.

綁定設備

當我們進行ANCS操作的時候,就會彈出配對的請求的對話框要求我們來完成配對,如果我們不進行配對的話,就無法對ANCS進行操作,同時GATT連接也會經常自動斷開連接。

因此我們一般是在掃描到設備后就與設備進行配對,完成配對后再與設備進行連接。

先判斷是否已經在配對列表中,是,則進行連接,不是,則進行配對:

 //已經綁定,該設備在綁定的設備名單里面
 if (mBluetoothAdapter.getBondedDevices().contains(device)) {

     device.connectGatt(getApplicationContext(), false, mGattCallback);
     mBluetoothLeScanner.stopScan(mScanCallback);
 } else {//未綁定的設備
     device.createBond();
 }

通過接受系統的BondStateChanged廣播接受綁定成功的消息:

if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
    if (intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1) == BluetoothDevice.BOND_BONDED) {
        showMessage("Bluetooth bond success!");
    }
}

操作ANCS

操作ANCS就是操作ANCS服務下的三個Characteristic,其操作也無非是BLE characteristic的三種操作:

  • 讀取(read)
  • 寫入(write)
  • 通知(setNotification)

詳細可見最后一章參考文章《Android BLE開發之玩轉小米手環》。

因為需要通過對Notification Source、Data Source、Control Point進行讀寫通知操作完成所有的功能,因此對操作的流程、通知數據包的格式、命令的格式進行了規定,相當于應用層的協議,具體的可以參考ANCS分析的兩篇文章。

  • Notification Source(setNotification):獲取通知基本信息
  • Data Source(setNotification):獲取通知的詳細信息
  • Control Point (write): 寫入通知控制命令

接下來我們主要從代碼上來說明如何操作。

獲取通知
  1. Data Source通知開啟
 private void setNotificationEnabled(BluetoothGattCharacteristic characteristic) {
    mConnectedGatt.setCharacteristicNotification(characteristic, true);
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(Constants.descriptor_config));
    if (descriptor != null) {
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mConnectedGatt.writeDescriptor(descriptor);
    }
}
  1. Data Source開啟后,Notification Source通知開啟。
  2. Notification Source的回調中獲取通知基本信息。
System.out.println(
    "EventId:" + String.format("%d", nsData[0]) + "\n" +
    "EventFlags:" + String.format("%02x", nsData[1]) + "\n" +
    "Category id:" + String.format("%d", nsData[2]) + "\n" +
    "Category Count:" + String.format("%d", nsData[3]) + "\n" +
    "NotificationUId:" + String.format("%02X", nsData[4]) + String.format("%02X", nsData[5])+ String.format("%02X", nsData[6]) + String.format("%02X", nsData[7]) + "\n"
);
  1. 往Control Point中寫入獲取更多通知信息的命令。
 private void getMoreAboutNotification(byte[] nsData) {
        byte[] getNotificationAttribute = {
        (byte) 0x00,
        //UID
        nsData[4], nsData[5], nsData[6], nsData[7],
        //app id
        (byte) 0x00,
        //title
        (byte) 0x01, (byte) 0xff, (byte) 0xff,
        //message
        (byte) 0x03, (byte) 0xff, (byte) 0xff
    };

    if (mConnectedGatt != null) {
        mPointControlChar.setValue(getNotificationAttribute);
        mConnectedGatt.writeCharacteristic(mPointControlChar);
    }
}
  1. Data Source的回調中獲取更多信息。
    具體解析參見相關閱讀中ANCS分析的兩篇文章。
執行相應動作
  1. 解析eventFlags中的通知動作。
    public int getAction() {

        action = 0;
        //positive標志位為1
        if ((eventFlags & 0x08) > 0) {
            action = action + 1;
        }
        //negative標志位為1
        if ((eventFlags & 0x10) > 0) {
            action = action + 2;
        }
        return action;
    }
  1. 寫入動作命令到Control Point中。
byte[] action = {
        (byte) 0x02,
        //UID
        nid[0], nid[1], nid[2], nid[3],
        //positive action id(二選一)
        (byte) 0x00,
        //negative action id(二選一)
        (byte)0x01,
};

Demo

Github地址:ANCSReader

  • 接收系統通知基本的信息,包括標題、類型(消息、來電等)、狀態(產生、修改、刪除)
  • 接收通知的詳細信息,包括內容、應用、時間等各種信息。
  • 對通知采取相應的操作

相關閱讀

** Android BLE開發相關知識 **
Android BLE開發之初識GATT
Android BLE開發之玩轉小米手環

** ANCS相關知識 **
蘋果通知中心服務ANCS協議分析
蘋果通知中心服務ANCS協議分析二

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容