https://linkingiot.com/developer/#developers より引用はじめに
NTTドコモ等の複数の国内企業が連携して「Linking」というプラットフォームが発表されました。
公開されたサイトを見てみると、どうやらLinkingとはIoT(Internet of Things)に関係するらしいフレーズが散りばめられています。
- すべてのモノが、ネットでつながる
- デバイス開発者も、アプリ開発者も、そしてユーザーも。
- Linkingプラットフォームが、つくるをつなぐ。
https://linkingiot.com/developer/#developers より引用はじめに
https://linkingiot.com/developer/#developers より引用はじめに
BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager != null) { BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter(); }次にGATT Serverのインスタンスを取得します。(BluetoothManager#openGattServer)
mGattServer = mBluetoothManager.openGattServer(this, new BLEServer()); class BLEServer extends BluetoothGattServerCallback { //セントラルから読み込み要求が来ると呼ばれる public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { } //セントラルから書き込み要求が来ると呼ばれる public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { } }
private void setServices() { //serviceUUIDを設定BluetoothGattService service = new BluetoothGattService( UUID.fromString(Constants.SERVICE_UUID), BluetoothGattService.SERVICE_TYPE_PRIMARY); //characteristicUUIDを設定 BluetoothGattCharacteristic charRead = new BluetoothGattCharacteristic( UUID.fromString(Constants.CHAR_READ_UUID), BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ); BluetoothGattCharacteristic charWrite = new BluetoothGattCharacteristic( UUID.fromString(Constants.CHAR_WRITE_UUID), BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE); //characteristicUUIDをserviceUUIDにのせる service.addCharacteristic(charRead); service.addCharacteristic(charWrite); //serviceUUIDをサーバーにのせる mGattServer.addService(service); }次にアドバタイジング時の設定(AdvertiseSettings)とデータ(AdvertiseData)の設定を行います。
//AdvertiseSettingsの設定 private AdvertiseSettings buildAdvertiseSettings() { AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder(); settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER); settingsBuilder.setTimeout(0); return settingsBuilder.build(); } //AdvertiseDataの設定 private AdvertiseData buildAdvertiseData() { AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder(); dataBuilder.addServiceUuid(ParcelUuid.fromString(Constants.SERVICE_UUID)); dataBuilder.setIncludeDeviceName(true); return dataBuilder.build(); } //Advertiseの開始 private void startAdvertising() { setServices(); AdvertiseSettings settings = buildAdvertiseSettings(); AdvertiseData data = buildAdvertiseData(); mAdvertiseCallback = new SimpleAdvertiseCallback(); mBluetoothLeAdvertiser.startAdvertising(settings, data,mAdvertiseCallback); } //Advertiseの成功可否 private class SimpleAdvertiseCallback extends AdvertiseCallback { @Override public void onStartFailure(int errorCode) { super.onStartFailure(errorCode); Log.d(TAG, "Advertising failed"); } @Override public void onStartSuccess(AdvertiseSettings settingsInEffect) { super.onStartSuccess(settingsInEffect); Log.d(TAG, "Advertising successfully started"); } }
private void stopAdvertising() { Log.d(TAG, "Service: Stopping Advertising"); if (mGattServer != null) { mGattServer.clearServices(); mGattServer.close(); mGattServer = null; } if (mBluetoothLeAdvertiser != null) { mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback); mAdvertiseCallback = null; } }以上で、Nexus 9がペリフェラルとして機能するようになります。
public void readCharacteristic() { BluetoothGattCharacteristic read = mBluetoothLeService.getCharacteristic( GattAttributes.SERVICE_UUID, GattAttributes.CHAR_READ_UUID); mBluetoothGatt.readCharacteristic(read); } public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) { BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid)); if (s == null) { Log.w(TAG, "Service NoT found :" + sid); return null; } BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid)); if (c == null) { Log.w(TAG, "Characteristic NOT found :" + cid); return null; } return c; }
@Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { final byte[] data = characteristic.getValue(); Log.d(TAG, "onCharacteristicRead : " + new String(data)); }
//セントラルからReadRequestが来ると呼ばれる public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { //セントラルに任意の文字を返信する if (UUID.fromString(Constants. CHAR_READ_UUID).equals(characteristic.getUuid())) { String response = "your message."; byte value[] = response.getBytes(); mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); } }
public void writeCharacteristic() { BluetoothGattCharacteristic write = getCharacteristic( UUID.fromString(GattAttributes.SERVICE_UUID), UUID.fromString(GattAttributes.CHAR_WRITE_UUID)); String message = "your message"; write.setValue(message); mBluetoothGatt.writeCharacteristic(characteristic); } public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) { BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid)); if (s == null) { Log.w(TAG, "Service NoT found :" + sid); return null; } BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid)); if (c == null) { Log.w(TAG, "Characteristic NOT found :" + cid); return null; } return c; }
//セントラルから書き込み要求が来ると呼ばれる public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { Log.d(TAG, "onCharacteristicWriteRequest"); if (UUID.fromString(Constants.CHAR_WRITE_UUID).equals(characteristic.getUuid())) { final byte[] data = characteristic.getValue(); Log.d(TAG, "onCharacteristicRead : " + new String(data)); mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null); } }
BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager != null) { BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter(); }次にGATT Serverのインスタンスを取得します。(BluetoothManager#openGattServer)
mGattServer = mBluetoothManager.openGattServer(this, new BLEServer()); class BLEServer extends BluetoothGattServerCallback { //セントラルから読み込み要求が来ると呼ばれる public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { } //セントラルから書き込み要求が来ると呼ばれる public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { } }
private void setServices() { //serviceUUIDを設定BluetoothGattService service = new BluetoothGattService( UUID.fromString(Constants.SERVICE_UUID), BluetoothGattService.SERVICE_TYPE_PRIMARY); //characteristicUUIDを設定 BluetoothGattCharacteristic charRead = new BluetoothGattCharacteristic( UUID.fromString(Constants.CHAR_READ_UUID), BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ); BluetoothGattCharacteristic charWrite = new BluetoothGattCharacteristic( UUID.fromString(Constants.CHAR_WRITE_UUID), BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE); //characteristicUUIDをserviceUUIDにのせる service.addCharacteristic(charRead); service.addCharacteristic(charWrite); //serviceUUIDをサーバーにのせる mGattServer.addService(service); }次にアドバタイジング時の設定(AdvertiseSettings)とデータ(AdvertiseData)の設定を行います。
//AdvertiseSettingsの設定 private AdvertiseSettings buildAdvertiseSettings() { AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder(); settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER); settingsBuilder.setTimeout(0); return settingsBuilder.build(); } //AdvertiseDataの設定 private AdvertiseData buildAdvertiseData() { AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder(); dataBuilder.addServiceUuid(ParcelUuid.fromString(Constants.SERVICE_UUID)); dataBuilder.setIncludeDeviceName(true); return dataBuilder.build(); } //Advertiseの開始 private void startAdvertising() { setServices(); AdvertiseSettings settings = buildAdvertiseSettings(); AdvertiseData data = buildAdvertiseData(); mAdvertiseCallback = new SimpleAdvertiseCallback(); mBluetoothLeAdvertiser.startAdvertising(settings, data,mAdvertiseCallback); } //Advertiseの成功可否 private class SimpleAdvertiseCallback extends AdvertiseCallback { @Override public void onStartFailure(int errorCode) { super.onStartFailure(errorCode); Log.d(TAG, "Advertising failed"); } @Override public void onStartSuccess(AdvertiseSettings settingsInEffect) { super.onStartSuccess(settingsInEffect); Log.d(TAG, "Advertising successfully started"); } }
private void stopAdvertising() { Log.d(TAG, "Service: Stopping Advertising"); if (mGattServer != null) { mGattServer.clearServices(); mGattServer.close(); mGattServer = null; } if (mBluetoothLeAdvertiser != null) { mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback); mAdvertiseCallback = null; } }以上で、Nexus 9がペリフェラルとして機能するようになります。
public void readCharacteristic() { BluetoothGattCharacteristic read = mBluetoothLeService.getCharacteristic( GattAttributes.SERVICE_UUID, GattAttributes.CHAR_READ_UUID); mBluetoothGatt.readCharacteristic(read); } public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) { BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid)); if (s == null) { Log.w(TAG, "Service NoT found :" + sid); return null; } BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid)); if (c == null) { Log.w(TAG, "Characteristic NOT found :" + cid); return null; } return c; }
@Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { final byte[] data = characteristic.getValue(); Log.d(TAG, "onCharacteristicRead : " + new String(data)); }
//セントラルからReadRequestが来ると呼ばれる public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { //セントラルに任意の文字を返信する if (UUID.fromString(Constants. CHAR_READ_UUID).equals(characteristic.getUuid())) { String response = "your message."; byte value[] = response.getBytes(); mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); } }
public void writeCharacteristic() { BluetoothGattCharacteristic write = getCharacteristic( UUID.fromString(GattAttributes.SERVICE_UUID), UUID.fromString(GattAttributes.CHAR_WRITE_UUID)); String message = "your message"; write.setValue(message); mBluetoothGatt.writeCharacteristic(characteristic); } public BluetoothGattCharacteristic getCharacteristic(String sid, String cid) { BluetoothGattService s = mBluetoothGatt.getService(UUID.fromString(sid)); if (s == null) { Log.w(TAG, "Service NoT found :" + sid); return null; } BluetoothGattCharacteristic c = s.getCharacteristic(UUID.fromString(cid)); if (c == null) { Log.w(TAG, "Characteristic NOT found :" + cid); return null; } return c; }
//セントラルから書き込み要求が来ると呼ばれる public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { Log.d(TAG, "onCharacteristicWriteRequest"); if (UUID.fromString(Constants.CHAR_WRITE_UUID).equals(characteristic.getUuid())) { final byte[] data = characteristic.getValue(); Log.d(TAG, "onCharacteristicRead : " + new String(data)); mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null); } }
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>※端末がBLEに対応しているかの確認
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "BLE未対応端末です", Toast.LENGTH_SHORT).show(); finish(); }
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> または <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>しかし、それだけではBLE機能を使用することは出来ません。。
private boolean checkPermission() { if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_LOCATION_STATE); return false; } return true; }
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (PERMISSIONS_REQUEST_LOCATION_STATE == requestCode) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 許可された場合 Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT).show(); } else { // 不許可だった場合 Toast.makeText(this, "権限を拒否されました", Toast.LENGTH_SHORT).show(); finish(); } } }
final BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();次に、端末のBluetoothが有効になっているかの確認を行います。
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Device scan callback. private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, final ScanResult result) { super.onScanResult(callbackType, result); if (result != null && result.getDevice() != null) { runOnUiThread(new Runnable() { @Override public void run() { mLeDeviceListAdapter.addDevice(result.getDevice()); mLeDeviceListAdapter.notifyDataSetChanged(); } }); } } };
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);接続が確立されると、BluetoothGattCallback#onConnectionStateChangeが呼ばれます。
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) { mBluetoothGatt.discoverServices(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); serviceList = gatt.getServices(); // サービスの内容を取得等処理を行う // 取得したサービスからBLEデバイスの情報を取得する }
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>※端末がBLEに対応しているかの確認
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "BLE未対応端末です", Toast.LENGTH_SHORT).show(); finish(); }
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> または <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>しかし、それだけではBLE機能を使用することは出来ません。。
private boolean checkPermission() { if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_LOCATION_STATE); return false; } return true; }
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (PERMISSIONS_REQUEST_LOCATION_STATE == requestCode) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 許可された場合 Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT).show(); } else { // 不許可だった場合 Toast.makeText(this, "権限を拒否されました", Toast.LENGTH_SHORT).show(); finish(); } } }
final BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();次に、端末のBluetoothが有効になっているかの確認を行います。
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Device scan callback. private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, final ScanResult result) { super.onScanResult(callbackType, result); if (result != null && result.getDevice() != null) { runOnUiThread(new Runnable() { @Override public void run() { mLeDeviceListAdapter.addDevice(result.getDevice()); mLeDeviceListAdapter.notifyDataSetChanged(); } }); } } };
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);接続が確立されると、BluetoothGattCallback#onConnectionStateChangeが呼ばれます。
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) { mBluetoothGatt.discoverServices(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); serviceList = gatt.getServices(); // サービスの内容を取得等処理を行う // 取得したサービスからBLEデバイスの情報を取得する }
>ruby -v ruby 2.1.7p400 (2015-08-18 revision 51632) [x64-mingw32]
>gem install appium_lib
# encoding: utf-8 require "appium_lib" desired_caps = { caps: { platformName: "Android", deviceName: "Android Device", app: "#{Dir.pwd}/selendroid-test-app.apk", } } driver = Appium::Driver.new(desired_caps).start_driver Appium.promote_appium_methods Object button_element = find_element(:id, "io.selendroid.testapp:id/visibleButtonTest") button_element.click sleep 3 text_element = find_element(:id, "io.selendroid.testapp:id/visibleTextView") displayed_text = text_element.text button_element.click sleep 3 puts displayed_text driver.quit
>ruby sample.rb
>ruby -v ruby 2.1.7p400 (2015-08-18 revision 51632) [x64-mingw32]
>gem install appium_lib
# encoding: utf-8 require "appium_lib" desired_caps = { caps: { platformName: "Android", deviceName: "Android Device", app: "#{Dir.pwd}/selendroid-test-app.apk", } } driver = Appium::Driver.new(desired_caps).start_driver Appium.promote_appium_methods Object button_element = find_element(:id, "io.selendroid.testapp:id/visibleButtonTest") button_element.click sleep 3 text_element = find_element(:id, "io.selendroid.testapp:id/visibleTextView") displayed_text = text_element.text button_element.click sleep 3 puts displayed_text driver.quit
>ruby sample.rb
Android KitKat Hacks プロが教えるテクニック & ツール
株式会社ブリリアントサービス 著
NFC Hacks プロが教えるテクニック&ツール
株式会社ブリリアントサービス 著
Androidプログラミングの教科書
藤田 竜史、要 徳幸、住友 孝郎、日高 正博、小林 慎治、木村 尭海 著
入門Androidアプリケーションテスト
瀬戸 直喜/株式会社ブリリアントサービス 著
実践スマートフォンアプリケーション開発
株式会社ブリリアントサービス、八木 俊広、原 昇平、かわかみ ひろき 著
ジオモバイルプログラミング
郷田まり子/宅間俊志/近藤昭雄 著
ANDROID HACKS プロが教えるテクニック&ツール
株式会社ブリリアントサービス 著