Skip to content

Commit 6a8e90c

Browse files
author
Michał Pena
committed
Android 12 support #718
1 parent f0cf7fc commit 6a8e90c

File tree

6 files changed

+338
-4
lines changed

6 files changed

+338
-4
lines changed

plugin.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
<config-file target="AndroidManifest.xml" parent="/manifest">
2525
<uses-permission android:name="android.permission.BLUETOOTH"/>
2626
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
27+
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
28+
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
2729
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2830
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
2931
</config-file>

readme.md

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ This plugin allows you to interact with Bluetooth LE devices on Android, iOS, an
6161
- [isDiscovered](#isdiscovered)
6262
- [hasPermission](#haspermission)
6363
- [requestPermission](#requestpermission)
64+
- [hasPermissionBtScan](#haspermissionBtScan)
65+
- [requestPermissionBtScan](#requestpermissionBtScan)
66+
- [hasPermissionBtConnect](#haspermissionBtConnect)
67+
- [requestPermissionBtConnect](#requestpermissionBtConnect)
68+
- [hasPermissionBtAdvertise](#haspermissionBtAdvertise)
69+
- [requestPermissionBtAdvertise](#requestpermissionBtAdvertise)
6470
- [isLocationEnabled](#islocationenabled)
6571
- [requestLocation](#requestlocation)
6672
- [setPin](#setPin)
@@ -240,6 +246,12 @@ Neither Android nor iOS support Bluetooth on emulators, so you'll need to test o
240246
* [bluetoothle.isDiscovered](#isdiscovered)
241247
* [bluetoothle.hasPermission](#haspermission) (Android 6+)
242248
* [bluetoothle.requestPermission](#requestpermission) (Android 6+)
249+
* [bluetoothle.hasPermissionBtScan](#haspermissionBtScan) (Android 31+)
250+
* [bluetoothle.requestPermissionBtScan](#requestpermissionBtScan) (Android 31+)
251+
* [bluetoothle.hasPermissionBtConnect](#haspermissionBtConnect) (Android 31+)
252+
* [bluetoothle.requestPermissionBtConnect](#requestpermissionBtConnect) (Android 31+)
253+
* [bluetoothle.hasPermissionBtAdvertise](#haspermissionBtAdvertise) (Android 31+)
254+
* [bluetoothle.requestPermissionBtAdvertise](#requestpermissionBtAdvertise) (Android 31+)
243255
* [bluetoothle.isLocationEnabled](#islocationenabled) (Android 6+)
244256
* [bluetoothle.requestLocation](#requestlocation) (Android 6+)
245257
* [bluetoothle.retrievePeripheralsByAddress](#retrievePeripheralsByAddress) (iOS)
@@ -417,7 +429,7 @@ The successCallback contains the following properties:
417429

418430

419431
### startScan ###
420-
Scan for Bluetooth LE devices. Since scanning is expensive, stop as soon as possible. The Cordova app should use a timer to limit the scan interval. Also, Android uses an AND operator for filtering, while iOS uses an OR operator. Android API >= 23 requires ACCESS_COARSE_LOCATION permissions to find unpaired devices. Permissions can be requested by using the hasPermission and requestPermission functions. Android API >= 23 also requires location services to be enabled. Use ```isLocationEnabled``` to determine whether location services are enabled. If not enabled, use ```requestLocation``` to prompt the location services settings page.
432+
Scan for Bluetooth LE devices. Since scanning is expensive, stop as soon as possible. The Cordova app should use a timer to limit the scan interval. Also, Android uses an AND operator for filtering, while iOS uses an OR operator. Android API >= 23 requires ACCESS_COARSE_LOCATION permissions to find unpaired devices. Permissions can be requested by using the hasPermission and requestPermission functions. Android API >= 23 also requires location services to be enabled. Use ```isLocationEnabled``` to determine whether location services are enabled. If not enabled, use ```requestLocation``` to prompt the location services settings page. Android API >= 31 also requires BLUETOOTH_SCAN permissions to perform scanning. You can use ```hasPermissionBtScan``` to determine whether scanning permission is granted or use ```requestPermissionBtScan``` to prompt for it.
421433

422434
```javascript
423435
bluetoothle.startScan(startScanSuccess, startScanError, params);
@@ -616,7 +628,7 @@ bluetoothle.unbond(unbondSuccess, unbondError, params);
616628

617629

618630
### connect ###
619-
Connect to a Bluetooth LE device. The app should use a timer to limit the connecting time in case connecting is never successful. Once a device is connected, it may disconnect without user intervention. The original connection callback will be called again and receive an object with status => disconnected. To reconnect to the device, use the reconnect method. If a timeout occurs, the connection attempt should be canceled using disconnect(). For simplicity, I recommend just using connect() and close(), don't use reconnect() or disconnect().
631+
Connect to a Bluetooth LE device. The app should use a timer to limit the connecting time in case connecting is never successful. Once a device is connected, it may disconnect without user intervention. The original connection callback will be called again and receive an object with status => disconnected. To reconnect to the device, use the reconnect method. If a timeout occurs, the connection attempt should be canceled using disconnect(). For simplicity, I recommend just using connect() and close(), don't use reconnect() or disconnect(). Android API >= 31 requires BLUETOOTH_CONNECT permissions to connect to devices. You can use ```hasPermissionBtConnect``` to determine whether connect permission is granted or use ```requestPermissionBtConnect``` to prompt for it.
620632

621633
```javascript
622634
bluetoothle.connect(connectSuccess, connectError, params);
@@ -1739,6 +1751,114 @@ bluetoothle.requestPermission(requestPermissionSuccess, requestPermissionError);
17391751

17401752

17411753

1754+
### hasPermissionBtScan ###
1755+
Determine whether Bluetooth scanning privileges are granted since scanning for unpaired devices requies it in Android API 31
1756+
1757+
```javascript
1758+
bluetoothle.hasPermissionBtScan(hasPermissionSuccess);
1759+
```
1760+
1761+
##### Success #####
1762+
* status => hasPermission = true/false
1763+
1764+
```javascript
1765+
{
1766+
"hasPermission": true
1767+
}
1768+
```
1769+
1770+
1771+
1772+
### requestPermissionBtScan ###
1773+
Request Bluetooth scanning privileges since scanning for unpaired devices requires it in Android API 31. Will return an error if called on iOS or Android versions prior to 6.0.
1774+
1775+
```javascript
1776+
bluetoothle.requestPermissionBtScan(requestPermissionSuccess, requestPermissionError);
1777+
```
1778+
1779+
##### Success #####
1780+
* status => requestPermission = true/false
1781+
1782+
```javascript
1783+
{
1784+
"requestPermission": true
1785+
}
1786+
```
1787+
1788+
1789+
1790+
### hasPermissionBtConnect ###
1791+
Determine whether Bluetooth connect privileges are granted since connecting to unpaired devices requies it in Android API 31
1792+
1793+
```javascript
1794+
bluetoothle.hasPermissionBtConnect(hasPermissionSuccess);
1795+
```
1796+
1797+
##### Success #####
1798+
* status => hasPermission = true/false
1799+
1800+
```javascript
1801+
{
1802+
"hasPermission": true
1803+
}
1804+
```
1805+
1806+
1807+
1808+
### requestPermissionBtConnect ###
1809+
Request Bluetooth connect privileges since connecting to unpaired devices requires it in Android API 31. Will return an error if called on iOS or Android versions prior to 6.0.
1810+
1811+
```javascript
1812+
bluetoothle.requestPermissionBtConnect(requestPermissionSuccess, requestPermissionError);
1813+
```
1814+
1815+
##### Success #####
1816+
* status => requestPermission = true/false
1817+
1818+
```javascript
1819+
{
1820+
"requestPermission": true
1821+
}
1822+
```
1823+
1824+
1825+
1826+
### hasPermissionBtAdvertise ###
1827+
Determine whether Bluetooth advertise privileges are granted since making the current device discoverable requies it in Android API 31
1828+
1829+
```javascript
1830+
bluetoothle.hasPermissionBtAdvertise(hasPermissionSuccess);
1831+
```
1832+
1833+
##### Success #####
1834+
* status => hasPermission = true/false
1835+
1836+
```javascript
1837+
{
1838+
"hasPermission": true
1839+
}
1840+
```
1841+
1842+
1843+
1844+
### requestPermissionBtAdvertise ###
1845+
Request Bluetooth advertise privileges since making the current device discoverable requires it in Android API 31. Will return an error if called on iOS or Android versions prior to 6.0.
1846+
1847+
```javascript
1848+
bluetoothle.requestPermissionBtAdvertise(requestPermissionSuccess, requestPermissionError);
1849+
```
1850+
1851+
##### Success #####
1852+
* status => requestPermission = true/false
1853+
1854+
```javascript
1855+
{
1856+
"requestPermission": true
1857+
}
1858+
```
1859+
1860+
1861+
17421862
### isLocationEnabled ###
17431863
Determine if location services are enabled or not. Location Services are required to find devices in Android API 23.
17441864

@@ -2041,7 +2161,8 @@ bluetoothle.removeAllServices(success, error);
20412161

20422162
### startAdvertising ###
20432163
Start advertising as a BLE device. Note: This needs to be improved so services can be used for both Android and iOS.
2044-
On iOS, the advertising devices likes to rename itself back to the name of the device, i.e. Rand' iPhone
2164+
On iOS, the advertising devices likes to rename itself back to the name of the device, i.e. Rand' iPhone.
2165+
Android API >= 31 also requires BLUETOOTH_ADVERTISE permissions to perform advertising. You can use ```hasPermissionBtAdvertise``` to determine whether advertise permission is granted or use ```requestPermissionBtAdvertise``` to prompt for it.
20452166

20462167
```javascript
20472168
bluetoothle.startAdvertising(success, error, params);

src/android/BluetoothLePlugin.java

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ public class BluetoothLePlugin extends CordovaPlugin {
5959
private final int REQUEST_BT_ENABLE = 59627; /*Random integer*/
6060
private final int REQUEST_ACCESS_FINE_LOCATION = 59628;
6161
private final int REQUEST_LOCATION_SOURCE_SETTINGS = 59629;
62+
private final int REQUEST_BLUETOOTH_SCAN = 59630;
63+
private final int REQUEST_BLUETOOTH_ADVERTISE = 59631;
64+
private final int REQUEST_BLUETOOTH_CONNECT = 59632;
6265
private BluetoothAdapter bluetoothAdapter;
6366
private boolean isReceiverRegistered = false;
6467
private boolean isBondReceiverRegistered = false;
@@ -393,6 +396,18 @@ public boolean execute(String action, final JSONArray args, final CallbackContex
393396
hasPermissionAction(callbackContext);
394397
} else if ("requestPermission".equals(action)) {
395398
requestPermissionAction(callbackContext);
399+
} else if ("hasPermissionBtScan".equals(action)) {
400+
hasPermissionBtScanAction(callbackContext);
401+
} else if ("requestPermissionBtScan".equals(action)) {
402+
requestPermissionBtScanAction(callbackContext);
403+
} else if ("hasPermissionBtConnect".equals(action)) {
404+
hasPermissionBtConnectAction(callbackContext);
405+
} else if ("requestPermissionBtConnect".equals(action)) {
406+
requestPermissionBtConnectAction(callbackContext);
407+
} else if ("hasPermissionBtAdvertise".equals(action)) {
408+
hasPermissionBtAdvertiseAction(callbackContext);
409+
} else if ("requestPermissionBtAdvertise".equals(action)) {
410+
requestPermissionBtAdvertiseAction(callbackContext);
396411
} else if ("isLocationEnabled".equals(action)) {
397412
isLocationEnabledAction(callbackContext);
398413
} else if ("requestLocation".equals(action)) {
@@ -879,6 +894,10 @@ private void notifyAction(JSONArray args, CallbackContext callbackContext) {
879894
}
880895
}
881896

897+
/**
898+
* ACCESS_FINE_LOCATION
899+
*/
900+
882901
public void hasPermissionAction(CallbackContext callbackContext) {
883902
JSONObject returnObj = new JSONObject();
884903

@@ -900,6 +919,81 @@ public void requestPermissionAction(CallbackContext callbackContext) {
900919
cordova.requestPermission(this, REQUEST_ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION);
901920
}
902921

922+
/**
923+
* BLUETOOTH_SCAN
924+
*/
925+
926+
public void hasPermissionBtScanAction(CallbackContext callbackContext) {
927+
JSONObject returnObj = new JSONObject();
928+
929+
addProperty(returnObj, "hasPermission", cordova.hasPermission(Manifest.permission.BLUETOOTH_SCAN));
930+
931+
callbackContext.success(returnObj);
932+
}
933+
934+
public void requestPermissionBtScanAction(CallbackContext callbackContext) {
935+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
936+
JSONObject returnObj = new JSONObject();
937+
addProperty(returnObj, keyError, "requestPermission");
938+
addProperty(returnObj, keyMessage, logOperationUnsupported);
939+
callbackContext.error(returnObj);
940+
return;
941+
}
942+
943+
permissionsCallback = callbackContext;
944+
cordova.requestPermission(this, REQUEST_BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_SCAN);
945+
}
946+
947+
/**
948+
* BLUETOOTH_CONNECT
949+
*/
950+
951+
public void hasPermissionBtConnectAction(CallbackContext callbackContext) {
952+
JSONObject returnObj = new JSONObject();
953+
954+
addProperty(returnObj, "hasPermission", cordova.hasPermission(Manifest.permission.BLUETOOTH_CONNECT));
955+
956+
callbackContext.success(returnObj);
957+
}
958+
959+
public void requestPermissionBtConnectAction(CallbackContext callbackContext) {
960+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
961+
JSONObject returnObj = new JSONObject();
962+
addProperty(returnObj, keyError, "requestPermission");
963+
addProperty(returnObj, keyMessage, logOperationUnsupported);
964+
callbackContext.error(returnObj);
965+
return;
966+
}
967+
968+
permissionsCallback = callbackContext;
969+
cordova.requestPermission(this, REQUEST_BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_CONNECT);
970+
}
971+
972+
/**
973+
* BLUETOOTH_ADVERTISE
974+
*/
975+
976+
public void hasPermissionBtAdvertiseAction(CallbackContext callbackContext) {
977+
JSONObject returnObj = new JSONObject();
978+
979+
addProperty(returnObj, "hasPermission", cordova.hasPermission(Manifest.permission.BLUETOOTH_ADVERTISE));
980+
981+
callbackContext.success(returnObj);
982+
}
983+
984+
public void requestPermissionBtAdvertiseAction(CallbackContext callbackContext) {
985+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
986+
JSONObject returnObj = new JSONObject();
987+
addProperty(returnObj, keyError, "requestPermission");
988+
addProperty(returnObj, keyMessage, logOperationUnsupported);
989+
callbackContext.error(returnObj);
990+
return;
991+
}
992+
993+
permissionsCallback = callbackContext;
994+
cordova.requestPermission(this, REQUEST_BLUETOOTH_ADVERTISE, Manifest.permission.BLUETOOTH_ADVERTISE);
995+
}
996+
903997
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
904998
if (permissionsCallback == null) {
905999
return;
@@ -908,7 +1002,25 @@ public void onRequestPermissionResult(int requestCode, String[] permissions, int
9081002
//Just call hasPermission again to verify
9091003
JSONObject returnObj = new JSONObject();
9101004

911-
addProperty(returnObj, "requestPermission", cordova.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
1005+
switch (requestCode) {
1006+
case REQUEST_ACCESS_FINE_LOCATION:
1007+
addProperty(returnObj, "requestPermission", cordova.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
1008+
break;
1009+
case REQUEST_BLUETOOTH_SCAN:
1010+
addProperty(returnObj, "requestPermission", cordova.hasPermission(Manifest.permission.BLUETOOTH_SCAN));
1011+
break;
1012+
case REQUEST_BLUETOOTH_CONNECT:
1013+
addProperty(returnObj, "requestPermission", cordova.hasPermission(Manifest.permission.BLUETOOTH_CONNECT));
1014+
break;
1015+
case REQUEST_BLUETOOTH_ADVERTISE:
1016+
addProperty(returnObj, "requestPermission", cordova.hasPermission(Manifest.permission.BLUETOOTH_ADVERTISE));
1017+
break;
1018+
default:
1019+
addProperty(returnObj, keyError, "requestPermission");
1020+
addProperty(returnObj, keyMessage, logOperationUnsupported);
1021+
permissionsCallback.error(returnObj);
1022+
return;
1023+
}
9121024

9131025
permissionsCallback.success(returnObj);
9141026
}

types/ble.ext.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,42 @@ BluetoothlePlugin.Bluetoothle.prototype.hasPermission = function (success) { };
280280
BluetoothlePlugin.Bluetoothle.prototype.requestPermission = function (success) { };
281281

282282

283+
/**
284+
* @param {function(result:[object Object])} success
285+
*/
286+
BluetoothlePlugin.Bluetoothle.prototype.hasPermissionBtScan = function (success) { };
287+
288+
289+
/**
290+
* @param {function(result:[object Object])} success
291+
*/
292+
BluetoothlePlugin.Bluetoothle.prototype.requestPermissionBtScan = function (success) { };
293+
294+
295+
/**
296+
* @param {function(result:[object Object])} success
297+
*/
298+
BluetoothlePlugin.Bluetoothle.prototype.hasPermissionBtConnect = function (success) { };
299+
300+
301+
/**
302+
* @param {function(result:[object Object])} success
303+
*/
304+
BluetoothlePlugin.Bluetoothle.prototype.requestPermissionBtConnect = function (success) { };
305+
306+
307+
/**
308+
* @param {function(result:[object Object])} success
309+
*/
310+
BluetoothlePlugin.Bluetoothle.prototype.hasPermissionBtAdvertise = function (success) { };
311+
312+
313+
/**
314+
* @param {function(result:[object Object])} success
315+
*/
316+
BluetoothlePlugin.Bluetoothle.prototype.requestPermissionBtAdvertise = function (success) { };
317+
318+
283319
/**
284320
* @param {function(result:[object Object])} isLocationEnabledSuccess
285321
* @param {function(error:BluetoothlePlugin.Error)} isLocationEnabledError

0 commit comments

Comments
 (0)