Skip to content

CCS-105439 Add bluetooth & nfc methods #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@expressms/smartapp-sdk",
"version": "1.12.0-alpha.5",
"version": "1.12.0-alpha.9",
"description": "Smartapp SDK",
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",
Expand Down
113 changes: 11 additions & 102 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,103 +1,12 @@
import Bridge from '@expressms/smartapp-bridge'
import {
cleanCache,
clientStorageClear,
clientStorageGet,
clientStorageRemove,
clientStorageSet,
createDeeplink,
getAppVisibility,
getChats,
getConnectionStatus,
getLayoutType,
getSmartAppList,
getUnreadCounter,
handleDeeplink,
openChatMessage,
openClientSettings,
openGroupChat,
requestLocation,
searchCorporatePhonebook,
searchLocalPhonebook,
sendBotCommand,
subscribeClientEvents,
unsubscribeClientEvents,
} from './lib/client'
import { openFile, uploadFile, uploadFiles } from './lib/client/file'
import {
addContact,
createPersonalChat,
getContact,
openContactCard,
openPersonalChat,
requestSelfProfile,
sendMessage,
} from './lib/contacts'
import { useQuery } from './lib/helpers/helpers'
import { ready } from './lib/logging'
import { onNotification } from './lib/notification'
import {
getCredentials,
runWebCommandsPipeline,
setAllowedNavigationDomains,
setCredentials,
setWebResourceCookies,
} from './lib/proxy'
import {
closeSmartApp,
exitSmartAppToCatalog,
onBackPressed,
onMoveToRoot,
openSmartApp,
routingChanged,
} from './lib/routing'
export * from './lib/client'
export * from './lib/client/file'
export * from './lib/contacts'
export * from './lib/helpers/helpers'
export * from './lib/logging'
export * from './lib/notification'
export * from './lib/routing'
export * from './lib/proxy'
export * from './lib/devices'

export {
Bridge,
ready,
routingChanged,
onBackPressed,
addContact,
getContact,
createPersonalChat,
onNotification,
sendMessage,
openSmartApp,
openFile,
uploadFile,
uploadFiles,
exitSmartAppToCatalog,
useQuery,
openClientSettings,
getChats,
searchCorporatePhonebook,
sendBotCommand,
openGroupChat,
onMoveToRoot,
requestLocation,
openContactCard,
requestSelfProfile,
closeSmartApp,
getAppVisibility,
getConnectionStatus,
subscribeClientEvents,
unsubscribeClientEvents,
createDeeplink,
openChatMessage,
clientStorageGet,
clientStorageSet,
clientStorageRemove,
clientStorageClear,
openPersonalChat,
handleDeeplink,
searchLocalPhonebook,
getUnreadCounter,
getLayoutType,
cleanCache,
getSmartAppList,
setWebResourceCookies,
setAllowedNavigationDomains,
runWebCommandsPipeline,
getCredentials,
setCredentials,
}
import Bridge from '@expressms/smartapp-bridge'
export { Bridge }
8 changes: 0 additions & 8 deletions src/lib/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,6 @@ const sendBotCommand = ({
})
}

const requestLocation = () => {
return bridge?.sendClientEvent({
method: METHODS.REQUEST_LOCATION,
params: {},
})
}

/**
* Get client current connection status. It's based on client's WebSocket connection state.
* @returns Promise that'll be fullfilled with status data on success, otherwise rejected with reason
Expand Down Expand Up @@ -243,7 +236,6 @@ export {
searchCorporatePhonebook,
openGroupChat,
sendBotCommand,
requestLocation,
getConnectionStatus,
createDeeplink,
openChatMessage,
Expand Down
195 changes: 195 additions & 0 deletions src/lib/devices/bluetooth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import bridge from '@expressms/smartapp-bridge'
import {
BleDeviceCallback,
BluetoothBleDeviceFoundEvent,
BluetoothDiscoverGattServicesResponse,
BluetoothReadBleGattCharacteristicResponse,
BluetoothScanBleDevicesResponse,
BluetoothStatusResponse,
ERROR_CODES,
METHODS,
} from '../../types'

const deviceCallbacks: Array<BleDeviceCallback> = []

/**
* Install bridge event listener for founded devices during scan
*/
const installBridgeEventListener = () => {
if (!bridge) return

bridge.onReceive(event => {
if (event.type !== 'ble_device_found') return

const {
payload: { bleDevice },
} = event as BluetoothBleDeviceFoundEvent

deviceCallbacks.map(cb => cb(bleDevice))
})
}

/**
* Add callback to list
*/
const addDeviceCallback = (callback?: BleDeviceCallback) => {
if (callback) deviceCallbacks.push(callback)
}

/**
* Remove callback from list
*/
const removeDeviceCallback = (callback?: BleDeviceCallback) => {
if (!callback) return

const index = deviceCallbacks.findIndex(cb => cb === callback)
if (index !== -1) deviceCallbacks.splice(index, 1)
}

/**
* Enable bluetooth
* @returns Promise that'll be fullfilled on success, otherwise rejected with reason
*/
export const enable = (): Promise<BluetoothStatusResponse> => {
if (!bridge) return Promise.reject(ERROR_CODES.NO_BRIDGE)

return bridge
.sendClientEvent({
method: METHODS.ENABLE_BLUETOOTH,
params: {},
})
.then(event => event as BluetoothStatusResponse)
}

/**
* Scan BLE devices nearby
* @param scanDuration Duration to scan devices in milliseconds
* @param deviceCallback Callback that triggered on device found
* @returns Promise that'll be fullfilled with `payload.bleDevices` on success, otherwise rejected with reason
*/
export const scanBleDevices = ({
scanDuration,
deviceCallback,
}: {
scanDuration: number
deviceCallback?: BleDeviceCallback
}): Promise<BluetoothScanBleDevicesResponse> => {
if (!bridge) return Promise.reject(ERROR_CODES.NO_BRIDGE)

addDeviceCallback(deviceCallback)

return bridge
.sendClientEvent({
method: METHODS.SCAN_BLE_DEVICES,
params: {
scanDuration,
},
})
.then(event => {
removeDeviceCallback(deviceCallback)
return event as BluetoothScanBleDevicesResponse
})
.catch(() => {
removeDeviceCallback(deviceCallback)
return Promise.reject()
})
}

/**
* Connect bluetooth BLE device
* @param bleDeviceAddress Address of the BLE device
* @returns Promise that'll be fullfilled on success, otherwise rejected with reason
*/
export const connectBleDevice = ({
bleDeviceAddress,
}: {
bleDeviceAddress: string
}): Promise<BluetoothStatusResponse> => {
if (!bridge) return Promise.reject(ERROR_CODES.NO_BRIDGE)

return bridge
.sendClientEvent({
method: METHODS.CONNECT_BLE_DEVICE,
params: {
bleDeviceAddress,
},
})
.then(event => event as BluetoothStatusResponse)
}

/**
* Disonnect bluetooth BLE device
* @param bleDeviceAddress Address of the BLE device
* @returns Promise that'll be fullfilled on success, otherwise rejected with reason
*/
export const disconnectBleDevice = ({
bleDeviceAddress,
}: {
bleDeviceAddress: string
}): Promise<BluetoothStatusResponse> => {
if (!bridge) return Promise.reject(ERROR_CODES.NO_BRIDGE)

return bridge
.sendClientEvent({
method: METHODS.DISCONNECT_BLE_DEVICE,
params: {
bleDeviceAddress,
},
})
.then(event => event as BluetoothStatusResponse)
}

/**
* Discover services and characteristics of the BLE device
* @param bleDeviceAddress Address of the BLE device
* @returns Promise that'll be fullfilled with `payload.gattServices` on success, otherwise rejected with reason
*/
export const discoverGattServices = ({
bleDeviceAddress,
}: {
bleDeviceAddress: string
}): Promise<BluetoothDiscoverGattServicesResponse> => {
if (!bridge) return Promise.reject(ERROR_CODES.NO_BRIDGE)

return bridge
.sendClientEvent({
method: METHODS.DISCOVER_BLE_GATT_SERVICES,
params: {
bleDeviceAddress,
},
})
.then(event => event as BluetoothDiscoverGattServicesResponse)
}

/**
* Read BLE GATT characteristic
* @param bleDeviceAddress Address of the BLE device
* @param gattServiceUuid UUID of the GATT service
* @param gattCharacteristicUuid UUID of the GATT characteristic
* @returns Promise that'll be fullfilled with `payload.value` on success, otherwise rejected with reason
*/
export const readBleGattCharacteristic = ({
bleDeviceAddress,
gattServiceUuid,
gattCharacteristicUuid,
}: {
bleDeviceAddress: string,
gattServiceUuid: string,
gattCharacteristicUuid: string,
}): Promise<BluetoothReadBleGattCharacteristicResponse> => {
if (!bridge) return Promise.reject(ERROR_CODES.NO_BRIDGE)

return bridge
.sendClientEvent({
method: METHODS.READ_BLE_GATT_CHARACTERISTIC,
params: {
bleDeviceAddress,
gattServiceUuid,
gattCharacteristicUuid,
},
})
.then(event => event as BluetoothReadBleGattCharacteristicResponse)
}

// Init device event listener
installBridgeEventListener()
13 changes: 13 additions & 0 deletions src/lib/devices/gps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import bridge from '@expressms/smartapp-bridge'
import { METHODS } from '../../types'

/**
* Request GPS position
* @returns Promise that'll be fullfilled with `payload.*` on success, otherwise rejected with reason
*/
export const requestLocation = () => {
return bridge?.sendClientEvent({
method: METHODS.REQUEST_LOCATION,
params: {},
})
}
6 changes: 6 additions & 0 deletions src/lib/devices/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as Bluetooth from './bluetooth'
import * as GPS from './gps'
import { requestLocation } from './gps'
import * as NFC from './nfc'

export { Bluetooth, NFC, GPS, requestLocation }
21 changes: 21 additions & 0 deletions src/lib/devices/nfc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import bridge from '@expressms/smartapp-bridge'
import {
ERROR_CODES,
METHODS,
NfcReadTagResponse,
} from '../../types'

/**
* Enable bluetooth
* @returns Promise that'll be fullfilled with `payload.nfcTag` on success, otherwise rejected with reason
*/
export const readTag = (): Promise<NfcReadTagResponse> => {
if (!bridge) return Promise.reject(ERROR_CODES.NO_BRIDGE)

return bridge
.sendClientEvent({
method: METHODS.READ_NFC_TAG,
params: {},
})
.then(event => event as NfcReadTagResponse)
}
Loading