Версия DSBridge для HarmonyOS позволяет осуществлять взаимодействие между нативным кодом HarmonyOS и JavaScript. Библиотека поддерживает вызовы функций из одного пространства в другое.
В настоящее время библиотека поддерживает основные функции сторонних библиотек DSBridge для Android и iOS, сохраняя при этом основные способы использования. В будущем будет продолжена разработка, чтобы обеспечить соответствие функциональности библиотеки для Android, что позволит уменьшить адаптацию фронтенда и клиента.
Поскольку автор библиотеки DSBridge прекратил её поддержку, для Android рекомендуется использовать https://github.com/751496032/DSBridge-Android. В настоящее время я веду её поддержку.## Установка
Установка библиотеки:
ohpm install @hzw/ohos-dsbridge
или установка локального HAR-пакета
ohpm install ../libs/library.har
JsBridge
, реализуйте бизнес-API, используйте класс для централизованного управления API. Методы должны быть помечены аннотацией @JavaScriptInterface()
, что знакомо по Android. Аннотация @JavaScriptInterface()
используется для соблюдения стандартов и обеспечения согласованности с Android.export class JsBridge {
private cHandler: CompleteHandler = null
/**
* Синхронный метод
* @param p
* @returns
*/
@JavaScriptInterface(false)
testSync(p: string): string {
LogUtils.d("testSync: " + JSON.stringify(p))
return "hello native"
}
/**
* Асинхронный метод
* @param p
* @param handler
*/
@JavaScriptInterface()
testAsync(p: string, handler: CompleteHandler) {
LogUtils.d("testAsync: " + JSON.stringify(p))
this.cHandler = handler
}
}
Синхронные методы не поддерживают объявление с использованием async/await. Если требуется выполнить асинхронные задачи внутри синхронного метода, можно использовать функцию taskWait()
для завершения задач. Подробное описание будет дано ниже. Аргументы метода CompleteHandler
могут использоваться для асинхронного обратного вызова результатов.
WebViewControllerProxy
получаем экземпляр WebviewController
, чтобы внедрить JS, а затем связываем его с Web-компонентом. Затем связываем управляющий класс API (JsBridge) с WebViewControllerProxy
.```typescript
private controller: WebViewControllerProxy = WebViewControllerProxy.createController()aboutToAppear() { this.controller.addJavascriptObject(new JsBridge()) }
Web({ src: this.localPath, controller: this.controller.getWebViewController() }) .javaScriptAccess(true) .javaScriptProxy(this.controller.getJavaScriptProxy()) .onAlert((event) => { // AlertDialog.show({ message: event.message }) return false }) )
dsBridge
первый параметр — это имя нативного метода, второй параметр — это параметры, передаваемые нативному методу. Для асинхронных методов третий параметр — это обратный вызов, который принимает результат асинхронного обратного вызова CompleteHandler
.// синхронный вызов
let msg = dsBridge.call('testSync', JSON.stringify({data: 100}))
// асинхронный вызов
dsBridge.call('testAsync', JSON.stringify({data: 200}), (msg) => {
updateMsg(msg)
})
dsBridge
через CDN или npm. Если проект не имеет исторических обязательств, рекомендуется использовать пакет m-dsbridge
.npm i m-dsbridge
// или через CDN
<script src="https://cdn.jsdelivr.net/npm/m-dsbridge/dsBridge.js"></script>
Также поддерживается использование исходного JS-скрипта из библиотеки DSBridge для Android или iOS.
https://cdn.jsdelivr.net/npm/dsbridge/dist/dsbridge.js
dsBridge
регистрируем JS-функции для вызова нативными компонентами.// регистрация синхронной функции
dsBridge.register('showAlert', function (a, b, c) {
// return "Нативный вызов JS showAlert функции"
alert("Нативный вызов JS showAlert функции " + a + " " + b + " " + c)
return true
})
dsBridge.registerAsyn('showAlertAsync', function (a, b, c, callback) {
let counter = 0
let id = setInterval(() => {
if (counter < 5) {
callback(counter, false)
alert("Нативный вызов JS showAlertAsync функции" + a + " " + b + " " + c + " " + counter)
counter++
} else {
callback(counter, true)
alert("Нативный вызов JS showAlertAsync функции" + a + " " + b + " " + c + " " + counter)
clearInterval(id)
}
}, 1000)
})
В данном случае асинхронная функция `callback` завершает вызов всей цепочки, если последний параметр возвращает `true`. Если `false`, то можно продолжать вызовы обратно в нативную среду. Это и есть один вызов из JavaScript, который многократно возвращает результат. Например, если требуется непрерывно синхронизировать данные о прогрессе из JavaScript в нативную среду, это может быть полезно.
3. Нативная среда использует экземпляр `WebViewControllerProxy` для вызова функций, зарегистрированных в JavaScript.
```typescript
Кнопка("Вызов функции JS - синхронный")
.onClick(() => {
this.controller.callJs("showAlert", [1, 2, '666'], (v) => {
this.msg = v + ""
})
})
Кнопка("Вызов функции JS - асинхронный")
.onClick(() => {
this.controller.callJs("showAlertAsync", [1, 2, '666'], (v) => {
this.msg = v + ""
})
})
Метод callJs()
имеет три параметра: первый — это имя функции, зарегистрированной в JavaScript, второй — параметры, передаваемые функции, это массив, третий — функция, слушающая результаты возврата функции. Также предоставлен метод callHandler()
, аналогичный методу Android.## Обратный вызов прогресса (один вызов, много возвратов)
Ранее было упомянуто, что в JavaScript есть ситуация, когда один вызов многократно возвращает результаты. Это также поддерживается в нативной среде и имеет практическое применение, например, для непрерывного обновления прогресса загрузки из нативной среды в JavaScript. Это можно сделать с помощью метода CompleteHandler#setProgressData()
.
@JavaScriptInterface()
testAsync(p: string, handler: CompleteHandler) {
LogUtils.d("testAsync: " + JSON.stringify(p))
this.cHandler = handler
let counter = 0
setInterval(() => {
if (counter < 5) {
counter++
handler.setProgressData("Асинхронный возврат данных--" + counter)
} else {
this.cHandler.complete("Асинхронный возврат данных--окончание")
this.cHandler.complete("Асинхронный возврат данных--окончание2")
}
}, 1000)
JavaScript:
dsBridge.call('testAsync', JSON.stringify({data: 200}), (msg) => {
updateMsg(msg)
})
Вызов функции close()
из JavaScript может закрыть текущую страницу. Нативная среда может установить слушатель для наблюдения и перехвата этого события.
aboutToAppear() {
this.controller.setClosePageListener(() => {
return true; // false перехватит закрытие страницы
})
}
Возврат false
из обратного вызова функции блокирует событие закрытия страницы.
setProgressData
, закрытие страницы может привести к аварийному завершению. Чтобы избежать этой ситуации, рекомендуется завершить задачу в методе жизненного цикла компонента aboutToDisappear()
.```typescriptaboutToDisappear(){ this.jsBridge.destroy() }
## Пространства имен
Пространства имен помогают лучше управлять API, что особенно полезно при большом количестве API. Они позволяют классифицировать API по пространствам имен, разделённым символом `.`. Поддерживаются как синхронные, так и асинхронные вызовы.
### Пространства имен для нативных API
Для указания пространства имен используется `WebViewControllerProxy#addJavascriptObject`:
```typescript
this.controller.addJavascriptObject(new JsBridgeNamespace(), "namespace")
В JavaScript пространство имен используется для вызова соответствующих нативных функций:
const callNative6 = () => {
let msg = dsBridge.call('namespace.testSync', {msg: 'данные из пространства имен JS'})
updateMsg(msg)
}
const callNative7 = () => {
dsBridge.call('namespace.testAsync', 'test', (msg) => {
updateMsg(msg)
})
}
Пространства имен для JavaScript API регистрируются с помощью объекта dsBridge
:
// пространство имен
dsBridge.register('sync', {
test: function (a, b) {
return 'пространство имен: ' + (a + b)
}
})
dsBridge.registerAsync('async', {
test: function (a, b, callback) {
callback('пространство имен: ' + (a + b))
}
})
Первый параметр — это имя пространства имен, например sync
, второй параметр — это объект API, поддерживаются как литеральные объекты, так и экземпляры классов.
В нативных вызовах:
this.controller.callJs("sync.test", [1, 2], (value: string) => {
this.msg = value
})
``````markdown
this.controller.callJs("asny.test", [3, 2], (value: string) => {
this.msg = value
})
Синхронный метод нативного кода:
/**
* Шаблон синхронного метода
* @param p
* @returns
*/
@JavaScriptInterface(false)
testSync(p: string): string {
LogUtils.d("testSync: " + JSON.stringify(p))
return "синхронный метод нативного кода testSync возвращает данные"
}
Если нужно выполнить асинхронную задачу внутри синхронного метода и сразу вернуть результат асинхронной операции на H5, то текущее设计方案显然无法满足需求;在鸿蒙中,异步任务基本与Promise和async/await有关联,然而桥接函数不支持使用async/await声明(主要是由于鸿蒙Web脚本注入机制的限制,同时也为了兼容Android/iOS项目而设计的)。为此,创建了函数 taskWait()
以满足上述需求。该函数允许在同步方法中执行顺序异步任务,同时主线程同步等待异步结果。
/**
* Выполнение асинхронных параллельных задач в синхронном методе
* @param args
* @returns
*/
@JavaScriptInterface(false)
testTaskWait(args: string): number {
let p = new Param(100, 200)
let p1 = new Param(100, 300)
taskWait(p)
p1.tag = "Param"
taskWait(p1)
LogUtils.d(`testTaskWait sum: ${p.sum} ${p1.sum}`)
return p.sum + p1.sum
}
Класс Param
должен наследовать BaseSendable
и декорироваться с помощью декоратора @Sendable
. Задачи выполняются в методе run()
.
class Param extends BaseSendable {
constructor(public a: number, public b: number) {
super()
}
run(): Promise<number> {
return new Promise((resolve) => {
setTimeout(() => {
this.sum = this.a + this.b
resolve(this.sum)
}, 1000)
})
}
}
``````typescript
@Sendable
export class Param extends BaseSendable {
private a: number = 0
private b: number = 0
public sum: number = 0
public enableLog: boolean = true
constructor(a: number, b: number) {
super();
this.a = a;
this.b = b;
}
// Выполнение асинхронной задачи
async run(): Promise<void> {
this.sum = await this.add()
}
async add() {
return this.a + this.b
}
}
Функция taskWait()
является легковесной функцией синхронного ожидания и не рекомендуется для задач, выполняющихся слишком долго. Если задача не завершается в течение 3 секунд, ожидание автоматически завершается, что может привести к потере данных. Для длительных задач рекомендуется использовать асинхронные мостовые функции.
Спасибо @name718, @fjc0k и другим за поддержку и обратную связь. Приглашаем всех к обсуждению и улучшению экосистемы HarmonyOS.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )