Transport ガイド

Openloop SDK は複数の接続方式(Transport)をサポートしています。対象プラットフォームと用途(dApp / Native アプリ / Passkey Provider)に応じて適切な Transport を選択してください。

SDK 言語別パッケージ構成

Openloop SDK は TypeScript パッケージ群 (npm)Swift Package (SPM) の2系統で配布されています。

言語 / 形式 レジストリ 用途
TypeScript / npm npmjs.com (@openloop/*) Web dApp、Node.js / Electron、React Native (Connect Mobile を含む)
Swift / SPM openloop-connect/packages/mobile/ios/OpenloopShared/ iOS Native (Credential Provider Extension、ネイティブアプリ)
Kotlin / Maven (将来) Android Native
C# / NuGet (将来) Windows Native

プラットフォーム対応表

Transport Chrome/Edge Firefox Safari (Desktop) iOS Safari Android Chrome iOS Native Android Native Node.js / Electron
WebHID (USB)
Web Bluetooth
LocalWS
Safari Extension
USB HID (native)
BLE (Swift, OpenloopShared)
WalletConnect

WalletConnect はデバイスと直接通信するのではなく、Openloop Connect アプリ経由のリモート署名です。デバイス操作(アドレス取得等)は Connect アプリ側で行われます。

BLE (Swift, OpenloopShared): Openloop Connect の Credential Provider Extension が使用する BLE transport の Swift 実装。サードパーティ iOS アプリも同じ Swift Package を import すれば BLE 経由で Openloop と通信できます。Android 側の同等機能は Connect アプリ内 React Native レイヤから transport-ble を経由しています (将来 Kotlin native 化予定)。

選択フローチャート

Diagram 0

Passkey Provider 用途について: iOS / Android の Credential Manager 機能と統合する場合は Native アプリ + BLE transport を使います (Web ブラウザ用 transport は使えない)。実装例は Openloop Connect の CredentialProvider Extension (iOS) / OpenloopCredentialProviderService (Android) を参照。

各 Transport 詳細


WebHID (USB)

パッケージ: @openloop/transport-webhid 対応環境: Chrome 89+ / Edge 89+(デスクトップのみ)

USB ケーブルでデバイスを直接接続します。最も高速で安定した接続方式です。

Static メソッド

メソッド 説明
isSupported(): boolean WebHID API が利用可能か
connect(): Promise<WebHidTransport> デバイスピッカーを表示して接続(ユーザージェスチャー必要)
reconnect(): Promise<WebHidTransport \| null> 以前許可されたデバイスに自動再接続

コード例

import { WebHidTransport } from '@openloop/transport-webhid'

// サポート確認
if (!WebHidTransport.isSupported()) {
  console.log('WebHID is not supported in this browser')
}

// 初回接続(ボタンクリック内で)
const transport = await WebHidTransport.connect()

// 自動再接続(ページ読み込み時)
const transport = await WebHidTransport.reconnect()

// 切断検知
transport.onDisconnect(() => {
  console.log('Device disconnected')
})

Web Bluetooth

パッケージ: @openloop/transport-webble 対応環境: Chrome 56+ / Edge 79+(デスクトップ)、Android Chrome

Bluetooth Low Energy (BLE) でワイヤレス接続します。

Static メソッド

メソッド 説明
isSupported(): boolean Web Bluetooth API が利用可能か
connect(): Promise<WebBleTransport> デバイスピッカーを表示して接続(ユーザージェスチャー必要)
reconnect(): Promise<WebBleTransport \| null> 以前ペアリングしたデバイスに再接続(Chrome 100+)

コード例

import { WebBleTransport } from '@openloop/transport-webble'

if (!WebBleTransport.isSupported()) {
  console.log('Web Bluetooth is not supported')
}

// 初回接続
const transport = await WebBleTransport.connect()

// 自動再接続
const transport = await WebBleTransport.reconnect()

注意事項


LocalWS(全ブラウザ対応)

パッケージ: @openloop/transport-local 対応環境: WebSocket をサポートする全ブラウザ 前提条件: Openloop Connect デスクトップアプリが起動していること

Openloop Connect デスクトップアプリが提供する WebSocket サーバー(ws://127.0.0.1:21320)経由で通信します。Firefox、Safari 等の WebHID/WebBLE 非対応ブラウザでも動作します。

Static メソッド

メソッド 説明
isAvailable(port?, host?): Promise<boolean> Connect サーバーが稼働しているか

コード例

import { LocalWsTransport } from '@openloop/transport-local'

// Connect アプリの起動確認
const available = await LocalWsTransport.isAvailable()

// 接続
const transport = new LocalWsTransport({
  port: 21320,    // デフォルト
  host: '127.0.0.1', // デフォルト
})
await transport.open()

// デバイス接続状態の変更通知
transport.onDeviceChange((connected: boolean) => {
  console.log('Device:', connected ? 'connected' : 'disconnected')
})

プロトコル

JSON-RPC 2.0 over WebSocket:

メソッド 説明
openloop_exchange APDU コマンド送受信
openloop_lock デバイスの排他ロック取得
openloop_unlock デバイスの排他ロック解放
openloop_status デバイス接続状態の取得

Safari Extension(iOS)

パッケージ: @openloop/transport-safari 対応環境: iOS Safari(Openloop Safari Extension インストール済み)

Safari Web Extension を経由して iOS の CoreBluetooth にアクセスし、BLE でデバイスと通信します。

Static メソッド

メソッド 説明
isAvailable(timeout?): Promise<boolean> Safari Extension がインストールされているか(デフォルト 3 秒タイムアウト)
scan(duration?): Promise<DeviceInfo[]> BLE デバイスをスキャン
connect(deviceId?): Promise<SafariTransport> デバイスに接続

コード例

import { SafariTransport } from '@openloop/transport-safari'

// Extension の確認
const available = await SafariTransport.isAvailable()

// デバイスのスキャン
const devices = await SafariTransport.scan(5000) // 5秒スキャン
console.log('Found devices:', devices)

// 接続
const transport = await SafariTransport.connect(devices[0]?.deviceId)

USB HID (Native)

パッケージ: @openloop/transport-usb 対応環境: Node.js / Electron 依存: node-hid

ブラウザを使わずに直接 USB デバイスと通信します。サーバーサイドやデスクトップアプリに適しています。

Static メソッド

メソッド 説明
discover(): UsbDeviceInfo[] 接続されている Openloop/Ledger デバイスを列挙

コード例

import { UsbHidTransport } from '@openloop/transport-usb'

// デバイス検出
const devices = UsbHidTransport.discover()
if (devices.length === 0) {
  console.log('No device found')
}

// 接続
const transport = new UsbHidTransport({ path: devices[0].path })
await transport.open()

// 自動リトライ(デフォルト最大3回)
const transport = new UsbHidTransport({
  path: devices[0].path,
  maxRetries: 3,
  exchangeTimeout: 120000, // 2分
})

Swift BLE (OpenloopShared)

パッケージ: Swift Package, ローカル参照 openloop-connect/packages/mobile/ios/OpenloopShared/ 対応環境: iOS 17+ Native アプリ (Credential Provider Extension、ネイティブ iOS アプリ) 主要型: - BleManager — BLE スキャン / 接続 / GATT 通信 - BleTransportITransport 相当のSwift プロトコル実装 - Ctap2Builder — CTAP2 (FIDO2) のCBOR encode/decode、F0 B0 APDU tunnel 経由でFW と通信

ユースケース

主に iOS の Credential Provider Extension が WebAuthn passkey 認証を BLE 経由で Openloop に委譲する目的で使用します。サードパーティ製の iOS native アプリも同様に使用可能です。

コード例

import OpenloopShared

// BLE接続
let transport = BleTransport(manager: .shared, targetUUID: targetUUID)
try await transport.open()

// CTAP2 makeCredential (passkey 登録)
let ctap = Ctap2Builder(transport: transport)
let result = try await ctap.makeCredential(MakeCredentialParams(
    clientDataHash: clientDataHash,
    rp: .init(id: rpId),
    user: .init(id: userHandle, name: userName),
    pubKeyCredParams: pubKeyCredParams,
    excludeList: nil,
    options: .init(rk: true, up: true, uv: true)
))

// CTAP2 getAssertion (passkey 認証)
let result = try await ctap.getAssertion(GetAssertionParams(
    rpId: rpId,
    clientDataHash: clientDataHash,
    allowList: allowList,
    options: .init(up: true, uv: true)
))

注意点


WalletConnect

パッケージ: @openloop/sdk-core(WcTransport は sdk-core に含まれる) 対応環境: WebSocket をサポートする全ブラウザ

WalletConnect v2 リレー経由で、リモートの Openloop Connect アプリと通信します。カスタムメソッド openloop_exchange を使って APDU コマンドを中継します。

詳細は WalletConnect 連携 を参照してください。


OpenloopSDK クラスによる自動検出

OpenloopSDK クラスを使うと、利用可能な Transport を自動検出して接続できます。

import { OpenloopSDK, EthereumApp, DEFAULT_ETH_PATH } from '@openloop/sdk-core'
import { WebHidTransport } from '@openloop/transport-webhid'
import { WebBleTransport } from '@openloop/transport-webble'
import { LocalWsTransport } from '@openloop/transport-local'

// Transport を登録
OpenloopSDK.registerTransport('webhid', {
  factory: () => WebHidTransport.connect(),
  name: 'WebHID (USB)',
  isAvailable: () => WebHidTransport.isSupported(),
})

OpenloopSDK.registerTransport('webble', {
  factory: () => WebBleTransport.connect(),
  name: 'Web Bluetooth',
  isAvailable: () => WebBleTransport.isSupported(),
})

OpenloopSDK.registerTransport('local', {
  factory: async () => {
    const t = new LocalWsTransport()
    await t.open()
    return t
  },
  name: 'LocalWS (Connect)',
  isAvailable: () => LocalWsTransport.isAvailable(),
})

// 利用可能な Transport を確認
const transports = await OpenloopSDK.discover()
console.log(transports)
// [
//   { type: 'webhid', name: 'WebHID (USB)', available: true },
//   { type: 'webble', name: 'Web Bluetooth', available: true },
//   { type: 'local', name: 'LocalWS (Connect)', available: false },
// ]

// 指定した Transport で接続
const transport = await OpenloopSDK.connect({ transport: 'webhid' })

// または最初に利用可能な Transport で接続
const transport = await OpenloopSDK.connect()

再接続パターン

// ページ読み込み時に以前のデバイスへ自動再接続
async function autoReconnect(): Promise<ITransport | null> {
  // WebHID: 以前許可されたデバイスを検出
  if (WebHidTransport.isSupported()) {
    const transport = await WebHidTransport.reconnect()
    if (transport) return transport
  }

  // WebBLE: 以前ペアリングしたデバイスを検出(Chrome 100+)
  if (WebBleTransport.isSupported()) {
    const transport = await WebBleTransport.reconnect()
    if (transport) return transport
  }

  // LocalWS: Connect アプリが起動していれば接続
  if (await LocalWsTransport.isAvailable()) {
    const transport = new LocalWsTransport()
    await transport.open()
    return transport
  }

  return null
}

次のステップ