Skip to content
Closed
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
66 changes: 64 additions & 2 deletions src/apps/desktop/src/api/browser_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,35 @@ pub async fn browser_webview_eval(
app: tauri::AppHandle,
request: WebviewEvalRequest,
) -> Result<(), String> {
Err("Webview not found".to_string())
#[cfg(not(target_env = "ohos"))]
{
let webview = app
.get_webview(&request.label)
.ok_or_else(|| format!("Webview not found: {}", request.label))?;

webview
.eval(&request.script)
.map_err(|e| format!("eval failed: {e}"))
}
#[cfg(target_env = "ohos")]
{
use bitfun_core::util::JS_THREADSAFE_FUNCTION;
use napi_ohos::threadsafe_function::ThreadsafeFunctionCallMode;
use serde_json;

let _ = app;
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("browser_webview_eval").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function browser_webview_eval".to_owned());
};
let payload = serde_json::to_string(&request)
.map_err(|e| format!("Failed to serialize request: {e}"))?;
function.call(Ok(payload), ThreadsafeFunctionCallMode::NonBlocking);
Ok(())
}
}

#[derive(Debug, Deserialize)]
Expand All @@ -39,5 +67,39 @@ pub async fn browser_get_url(
app: tauri::AppHandle,
request: WebviewLabelRequest,
) -> Result<String, String> {
Err("Url is unavailable (webview URL is nil)".to_string())
#[cfg(not(target_env = "ohos"))]
{
let webview = app
.get_webview(&request.label)
.ok_or_else(|| format!("Webview not found: {}", request.label))?;

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| webview.url()));

match result {
Ok(Ok(url)) => Ok(url.to_string()),
Ok(Err(e)) => Err(format!("url failed: {e}")),
Err(_) => Err("url unavailable (webview URL is nil)".to_string()),
}
}
#[cfg(target_env = "ohos")]
{
use bitfun_core::util::JS_THREADSAFE_FUNCTION;

let _ = app;
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("browser_get_url").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function browser_get_url".to_owned());
};
let res = function.call_async(Ok(request.label)).await;
match res {
Ok(promise) => match promise.await {
Ok(url) => Ok(url),
Err(err) => Err(err.to_string()),
},
Err(err) => Err(err.to_string()),
}
}
}
21 changes: 21 additions & 0 deletions src/apps/ohos/entry/src/main/ets/entryability/EntryAbility.ets
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { BusinessError } from '@kit.BasicServicesKit';
import RustModule from 'libbitfun_desktop_lib.so';
import { CommonUtils } from '../utils/CommonUtils';
import { runDeveco } from '../utils/DevecoStart';
import { webViewManager } from '../utils/WebViewManager';


const DOMAIN = 0x0000;
Expand Down Expand Up @@ -188,6 +189,26 @@ export default class EntryAbility extends RustAbility {
}
return '';
});
RustModule.registerArktsFunction('browser_webview_eval', async (err: Error, payload: string): Promise<string> => {
interface WebviewEvalRequest {
label: string;
script: string;
}
try {
const request: WebviewEvalRequest = JSON.parse(payload);
return await webViewManager.evalJavaScript(request.label, request.script);
} catch (parseError) {
hilog.error(DOMAIN, 'vnext', `browser_webview_eval parse error: ${JSON.stringify(parseError)}`);
return `Failed to parse request: ${JSON.stringify(parseError)}`;
}
});
RustModule.registerArktsFunction('browser_get_url', async (err: Error, label: string): Promise<string> => {
const url = webViewManager.getUrl(label);
if (!url) {
return 'Url is unavailable (webview URL is nil)';
}
return url;
});
return super.onWindowStageCreate(windowStage);
}

Expand Down
45 changes: 45 additions & 0 deletions src/apps/ohos/entry/src/main/ets/pages/EmbeddedBrowserPage.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { webview } from '@kit.ArkWeb';
import { webViewManager } from '../utils/WebViewManager';
import { hilog } from '@kit.PerformanceAnalysisKit';

const DOMAIN = 0x0000;
const TAG = 'EmbeddedBrowserPage';

@Entry
@Component
struct EmbeddedBrowserPage {
@State url: string = 'https://openbitfun.com/';
@State label: string = 'embedded-browser-view-0';
controller: webview.WebviewController = new webview.WebviewController();

aboutToAppear(): void {
webViewManager.registerController(this.label, this.controller);
hilog.info(DOMAIN, TAG, `EmbeddedBrowserPage aboutToAppear, registered controller: ${this.label}`);
}

aboutToDisappear(): void {
webViewManager.unregisterController(this.label);
hilog.info(DOMAIN, TAG, `EmbeddedBrowserPage aboutToDisappear, unregistered controller: ${this.label}`);
}

build() {
Column() {
Web({ src: this.url, controller: this.controller })
.width('100%')
.height('100%')
.javaScriptAccess(true)
.domStorageAccess(true)
.onPageBegin((event) => {
hilog.info(DOMAIN, TAG, `Page begin: ${event?.url}`);
})
.onPageEnd((event) => {
hilog.info(DOMAIN, TAG, `Page end: ${event?.url}`);
})
.onErrorReceive((event) => {
hilog.error(DOMAIN, TAG, `Page error: ${event?.error.getErrorInfo()}`);
})
}
.width('100%')
.height('100%')
}
}
67 changes: 67 additions & 0 deletions src/apps/ohos/entry/src/main/ets/utils/WebViewManager.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { webview } from '@kit.ArkWeb';
import { hilog } from '@kit.PerformanceAnalysisKit';

const DOMAIN = 0x0000;
const TAG = 'WebViewManager';

export class WebViewManager {
private static instance: WebViewManager;
private controllers: Map<string, webview.WebviewController> = new Map();

static getInstance(): WebViewManager {
if (!WebViewManager.instance) {
WebViewManager.instance = new WebViewManager();
}
return WebViewManager.instance;
}

registerController(label: string, controller: webview.WebviewController): void {
this.controllers.set(label, controller);
hilog.info(DOMAIN, TAG, `Registered webview controller: ${label}`);
}

unregisterController(label: string): void {
this.controllers.delete(label);
hilog.info(DOMAIN, TAG, `Unregistered webview controller: ${label}`);
}

getController(label: string): webview.WebviewController | null {
return this.controllers.get(label) ?? null;
}

async evalJavaScript(label: string, script: string): Promise<string> {
const controller = this.getController(label);
if (!controller) {
hilog.error(DOMAIN, TAG, `Webview not found: ${label}`);
return `Webview not found: ${label}`;
}

try {
const result = await controller.runJavaScript(script);
hilog.info(DOMAIN, TAG, `evalJavaScript success: ${script}`);
return '';
} catch (error) {
hilog.error(DOMAIN, TAG, `evalJavaScript failed: ${JSON.stringify(error)}`);
return `eval failed: ${JSON.stringify(error)}`;
}
}

getUrl(label: string): string {
const controller = this.getController(label);
if (!controller) {
hilog.error(DOMAIN, TAG, `Webview not found: ${label}`);
return '';
}

try {
const url = controller.getUrl();
hilog.info(DOMAIN, TAG, `getUrl success: ${url}`);
return url;
} catch (error) {
hilog.error(DOMAIN, TAG, `getUrl failed: ${JSON.stringify(error)}`);
return '';
}
}
}

export const webViewManager = WebViewManager.getInstance();
1 change: 0 additions & 1 deletion src/web-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"@monaco-editor/react": "^4.6.0",
"@tanstack/react-virtual": "^3.13.23",
"@tauri-apps/api": "^2.10.1",
"@tauri-apps/plugin-autostart": "^2.0.0",
"@tauri-apps/plugin-dialog": "^2.6.0",
"@tauri-apps/plugin-fs": "^2.0.0",
"@tauri-apps/plugin-log": "^2.8.0",
Expand Down
31 changes: 0 additions & 31 deletions src/web-ui/src/infrastructure/api/service-api/SystemAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { api } from './ApiClient';
import { createTauriCommandError } from '../errors/TauriCommandError';
import { openUrl } from '@tauri-apps/plugin-opener';
import { disable as autostartDisable, enable as autostartEnable, isEnabled as autostartIsEnabled } from '@tauri-apps/plugin-autostart';
import { createLogger } from '@/shared/utils/logger';


Expand Down Expand Up @@ -172,19 +171,6 @@ export class SystemAPI {
}
}

/** Desktop only: whether the app is registered to launch at OS login. */
async getLaunchAtLoginEnabled(): Promise<boolean> {
if (typeof window === 'undefined' || !('__TAURI__' in window)) {
return false;
}
try {
return await autostartIsEnabled();
} catch (error) {
log.error('Failed to read launch-at-login state', error);
throw createTauriCommandError('autostart_is_enabled', error);
}
}

/** Desktop only: send an OS-level desktop notification. */
async sendSystemNotification(title: string, body?: string): Promise<void> {
if (typeof window === 'undefined' || !('__TAURI__' in window)) {
Expand All @@ -199,23 +185,6 @@ export class SystemAPI {
}
}

/** Desktop only: register or unregister launch at OS login. */
async setLaunchAtLoginEnabled(enabled: boolean): Promise<void> {
if (typeof window === 'undefined' || !('__TAURI__' in window)) {
return;
}
try {
if (enabled) {
await autostartEnable();
} else {
await autostartDisable();
}
} catch (error) {
log.error('Failed to set launch-at-login', { enabled, error });
throw createTauriCommandError('autostart_set', error, { enabled });
}
}

// ─── Window / Tray behavior ────────────────────────────────────────────────

/** Desktop only: immediately quit the application. */
Expand Down
Loading
Loading