-
Notifications
You must be signed in to change notification settings - Fork 5
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
β¨ (rn-hid) [DSDK-611]: React Native HID transport #662
base: feat/dsdk-610-rn-mobile-ble
Are you sure you want to change the base?
β¨ (rn-hid) [DSDK-611]: React Native HID transport #662
Conversation
The latest updates on your projects. Learn more about Vercel for Git βοΈ
1 Skipped Deployment
|
971ade3
to
b73908e
Compare
apps/mobile/App.tsx
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
temporary changes just to test the transport
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π
packages/transport/rn-hid/src/api/helpers/getObservableOfArraysNewItems.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GG. Just a few comments π
...ndroid/src/main/kotlin/com/ledger/devicesdk/shared/internal/service/stub/StubApduProvider.kt
Outdated
Show resolved
Hide resolved
...ransport/rn-hid/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/utils/Either.kt
Outdated
Show resolved
Hide resolved
} | ||
else -> {} | ||
} | ||
}.launchIn(CoroutineScope(Dispatchers.Default)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[COMMENT] You never stop collecting the flow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, done β
sendEvent(reactContext, BridgeEvents.TransportLog(info)) | ||
} | ||
|
||
private val transport: AndroidUsbTransport? by lazy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[ASK] Why is it nullable. In addition you never set it to null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[COMMENT] As it's lazy I ask myself if it'd be better to create all the instances in the init{} bloc instead of when we need the transport (meaning when calling the startScan()
method) to avoid losing timeπ€
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nullable because reactContext.currentActivity
can be null
so in that case it's set to null
.
The lazy initialization could be useful in case the DMK feature flag isn't enabled in LL. In that case we save some resources. But I'm not 100% sure it's necessary, I can also do that stuff in init...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes so I checked, the activity is null
when TransportHidModule is initialized. React Native's lifecycle is like that π€·ββοΈ
Looking at the implementation of ReactContext
, I can assume that activity won't be null when onResume
is called... So I could do the initialization there.
https://github.com/facebook/react-native/blob/f9bffef6c78091d3e89da5e3abba87d1b30b0b69/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java#L257-L261
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π
...nsport/rn-hid/android/src/main/kotlin/com/ledger/androidtransporthid/bridge/serialization.kt
Outdated
Show resolved
Hide resolved
InternalDeviceDisconnected, | ||
} from "@api/transport/types"; | ||
|
||
export class StubNativeModuleWrapper implements NativeModuleWrapper { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[ASK] Useful?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes for iOS. It would crash on iOS if we use DefaultNativeModuleWrapper as the native module does not exist in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π
val establishConnectionFn = { | ||
val sessionId = generateSessionId(id = device.deviceId.toString()) | ||
val newConnection = | ||
AndroidUsbDeviceConnection( | ||
usbManager = usbManager, | ||
usbDevice = device, | ||
ioDispatcher = Dispatchers.IO, | ||
framerService = FramerService(loggerService), | ||
request = UsbRequest(), | ||
) | ||
}.onEach { | ||
loggerService.log(info = buildSimpleInfoLogInfo( | ||
tag = "DefaultUsbTransport", | ||
message = "event received while connecting : $it") | ||
val connectedDevice = | ||
InternalConnectedDevice( | ||
sessionId, | ||
discoveryDevice.name, | ||
discoveryDevice.ledgerDevice, | ||
discoveryDevice.connectivityType, | ||
sendApduFn = { apdu -> newConnection.send(apdu) }, | ||
) | ||
}.first { | ||
it is UsbPermissionEvent.PermissionGranted || | ||
it is UsbPermissionEvent.PermissionDenied || | ||
it is UsbState.Detached | ||
} | ||
usbConnections[sessionId] = newConnection | ||
InternalConnectionResult.Connected(device = connectedDevice, sessionId = sessionId) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[COMMENT] Can be simplify without using a lambda and so creating a anonymous object :
override suspend fun connect(discoveryDevice: DiscoveryDevice): InternalConnectionResult {
.....
return if (device == null) {
InternalConnectionResult.ConnectionError(error = InternalConnectionResult.Failure.DeviceNotFound)
} else {
val sessionId = generateSessionId(id = device.deviceId.toString())
val newConnection =
AndroidUsbDeviceConnection(
usbManager = usbManager,
usbDevice = device,
framerService = FramerService(loggerService),
loggerService = loggerService,
request = UsbRequest(),
ioDispatcher = Dispatchers.IO,
)
val connectedDevice =
InternalConnectedDevice(
sessionId,
discoveryDevice.name,
discoveryDevice.ledgerDevice,
discoveryDevice.connectivityType,
sendApduFn = { apdu -> newConnection.send(apdu) },
)
usbConnections[sessionId] = newConnection
val establishConnection = InternalConnectionResult.Connected(device = connectedDevice, sessionId = sessionId)
if (usbManager.hasPermission(device)) {
return establishConnection
}
.....
}
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the end I extracted the permission check/request logic into a checkAndRequestPermission
method as it's reused now when a device gets attached (for reconnecting it)
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> | ||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> | ||
<!-- Android < 12 --> | ||
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> | ||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> | ||
<!-- common --> | ||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[ASK] Why do you need these permissions? Don't you just implement the USB transport?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is coming from the previous commits which my branch is based on, I need them because it includes the base for the sample app. And the sample app supports BLE, hence those permissions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad. My point here was : why don't you add these permissions in the transport/rn-hid/android/src/main instead of the app π
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean in rn-ble
? In the rn-ble
package, there is no native code, we use the react-native-ble-plx
which implements the native part. So we don't have control over the AndroidManifest there.
android { | ||
namespace "com.ledger.androidtransporthid" | ||
compileSdkVersion safeExtGet("compileSdkVersion", 34) | ||
|
||
defaultConfig { | ||
minSdkVersion safeExtGet("minSdkVersion", 30) | ||
targetSdkVersion safeExtGet("targetSdkVersion", 32) | ||
versionCode 1 | ||
versionName "1.0" | ||
} | ||
|
||
compileOptions { | ||
// Use JavaVersion enums for compatibility | ||
sourceCompatibility JavaVersion.VERSION_17 | ||
targetCompatibility JavaVersion.VERSION_17 | ||
} | ||
|
||
kotlinOptions { | ||
jvmTarget = jvmTargetVersion | ||
} | ||
|
||
lintOptions { | ||
abortOnError false | ||
warning 'InvalidPackage' | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[COMMENT] be careful. It turns out you don't use the same config that the android/app
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean exactly? You're talking about compileSdkVersion minSdkVersion and targetSdkVersion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you just need to create and use an constant π
return | ||
} | ||
|
||
CoroutineScope(Dispatchers.Default).launch { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[COMMENT] Prefer having only one scope as parameter of the class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, done β
b73908e
to
7e67d8c
Compare
54f0d21
to
3e7c087
Compare
3e7c087
to
8e0b3aa
Compare
31561a1
to
5c29afa
Compare
8e0b3aa
to
d8f5a1d
Compare
5c29afa
to
817ad9c
Compare
9b1a744
to
9010ec3
Compare
d8f5a1d
to
53d3009
Compare
53d3009
to
8098d27
Compare
...n/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/DefaultAndroidUsbTransport.kt
Outdated
Show resolved
Hide resolved
...m/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceApduSender.kt
Outdated
Show resolved
Hide resolved
ab624da
to
55ffc70
Compare
c58b34e
to
28e1239
Compare
28e1239
to
096449b
Compare
096449b
to
5a34415
Compare
π Description
RNHIDTransport
with a Native module + the TS layer on top.β Context
β Checklist
Pull Requests must pass CI checks and undergo code review. Set the PR as Draft if it is not yet ready for review.
π§ Checklist for the PR Reviewers