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 プロが教えるテクニック&ツール
株式会社ブリリアントサービス 著