Skip to content

Commit f96eecc

Browse files
committed
ArkWeb and hterm
1 parent 7fc6196 commit f96eecc

File tree

13 files changed

+23637
-19
lines changed

13 files changed

+23637
-19
lines changed

entry/build-profile.json5

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
{
22
"apiType": "stageMode",
33
"buildOption": {
4+
"externalNativeOptions": {
5+
"path": "./src/main/cpp/CMakeLists.txt",
6+
"arguments": "",
7+
"cppFlags": "",
8+
"abiFilters": [
9+
"arm64-v8a",
10+
"x86_64"
11+
]
12+
}
413
},
514
"buildOptionSet": [
615
{

entry/oh-package-lock.json5

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

entry/oh-package.json5

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"main": "",
66
"author": "",
77
"license": "",
8-
"dependencies": {}
8+
"dependencies": {
9+
"libentry.so": "file:./src/main/cpp/types/libentry"
10+
}
911
}
1012

entry/src/main/cpp/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# the minimum version of CMake.
2+
cmake_minimum_required(VERSION 3.5.0)
3+
project(MyApplication)
4+
5+
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
6+
7+
if(DEFINED PACKAGE_FIND_FILE)
8+
include(${PACKAGE_FIND_FILE})
9+
endif()
10+
11+
include_directories(${NATIVERENDER_ROOT_PATH}
12+
${NATIVERENDER_ROOT_PATH}/include)
13+
14+
add_library(entry SHARED napi_init.cpp)
15+
target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)

entry/src/main/cpp/napi_init.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include "napi/native_api.h"
2+
#include <algorithm>
3+
#include <array>
4+
#include <assert.h>
5+
#include <cstdint>
6+
#include <deque>
7+
#include <fcntl.h>
8+
#include <map>
9+
#include <poll.h>
10+
#include <pthread.h>
11+
#include <pty.h>
12+
#include <set>
13+
#include <stdint.h>
14+
#include <stdlib.h>
15+
#include <string>
16+
#include <sys/time.h>
17+
#include <unistd.h>
18+
#include <vector>
19+
20+
static int width = 127;
21+
static int height = 36;
22+
23+
static int fd = -1;
24+
25+
static napi_value Add(napi_env env, napi_callback_info info) {
26+
size_t argc = 2;
27+
napi_value args[2] = {nullptr};
28+
29+
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
30+
31+
napi_valuetype valuetype0;
32+
napi_typeof(env, args[0], &valuetype0);
33+
34+
napi_valuetype valuetype1;
35+
napi_typeof(env, args[1], &valuetype1);
36+
37+
double value0;
38+
napi_get_value_double(env, args[0], &value0);
39+
40+
double value1;
41+
napi_get_value_double(env, args[1], &value1);
42+
43+
napi_value sum;
44+
napi_create_double(env, value0 + value1, &sum);
45+
46+
return sum;
47+
}
48+
49+
static void *terminal_worker(void *) {}
50+
51+
static napi_value Run(napi_env env, napi_callback_info info) {
52+
53+
size_t argc = 2;
54+
napi_value args[2] = {nullptr};
55+
56+
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
57+
58+
napi_valuetype valuetype0;
59+
napi_typeof(env, args[0], &valuetype0);
60+
61+
napi_valuetype valuetype1;
62+
napi_typeof(env, args[1], &valuetype1);
63+
64+
double value0;
65+
napi_get_value_double(env, args[0], &value0);
66+
67+
double value1;
68+
napi_get_value_double(env, args[1], &value1);
69+
70+
width = value0;
71+
height = value1;
72+
73+
if (!fd) {
74+
struct winsize ws = {};
75+
ws.ws_col = width;
76+
ws.ws_row = height;
77+
int pid = forkpty(&fd, nullptr, nullptr, &ws);
78+
79+
if (!pid) {
80+
const char *home = "/storage/Users/currentUser";
81+
setenv("HOME", home, 1);
82+
setenv("PWD", home, 1);
83+
84+
chdir(home);
85+
execl("/bin/sh", "/bin/sh", nullptr);
86+
}
87+
88+
// set as non blocking
89+
int res = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
90+
assert(res == 0);
91+
92+
// start terminal worker in another thread
93+
pthread_t terminal_thread;
94+
pthread_create(&terminal_thread, NULL, terminal_worker, nullptr);
95+
}
96+
97+
return nullptr;
98+
}
99+
100+
// send data to terminal
101+
static napi_value send(napi_env env, napi_callback_info info) {
102+
103+
size_t argc = 1;
104+
napi_value args[1] = {nullptr};
105+
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
106+
107+
void *data;
108+
size_t length;
109+
napi_status ret = napi_get_arraybuffer_info(env, args[0], &data, &length);
110+
assert(ret == napi_ok);
111+
112+
// SendData((uint8_t *)data, length);
113+
return nullptr;
114+
}
115+
116+
EXTERN_C_START
117+
static napi_value Init(napi_env env, napi_value exports) {
118+
napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
119+
{"run", nullptr, Run, nullptr, nullptr, nullptr, napi_default, nullptr},
120+
{"send", nullptr, send, nullptr, nullptr, nullptr, napi_default, nullptr}};
121+
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
122+
return exports;
123+
}
124+
EXTERN_C_END
125+
126+
static napi_module demoModule = {
127+
.nm_version = 1,
128+
.nm_flags = 0,
129+
.nm_filename = nullptr,
130+
.nm_register_func = Init,
131+
.nm_modname = "entry",
132+
.nm_priv = ((void *)0),
133+
.reserved = {0},
134+
};
135+
136+
extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const add: (a: number, b: number) => number;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "libentry.so",
3+
"types": "./Index.d.ts",
4+
"version": "1.0.0",
5+
"description": "Please describe the basic information."
6+
}

entry/src/main/ets/entryability/EntryAbility.ets

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default class EntryAbility extends UIAbility {
1515
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
1616
}
1717

18-
onWindowStageCreate(windowStage: window.WindowStage): void {
18+
async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
1919
// Main window is created, set main page for this ability
2020
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
2121

@@ -28,10 +28,8 @@ export default class EntryAbility extends UIAbility {
2828
});
2929

3030
const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
31-
atManager.requestPermissionsFromUser(this.context, ['ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY']).then((data) => {
32-
atManager.requestPermissionsFromUser(this.context, ['ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY']).then((data) => {
33-
});
34-
});
31+
await atManager.requestPermissionsFromUser(this.context, ['ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY']);
32+
await atManager.requestPermissionsFromUser(this.context, ['ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY']);
3533
}
3634

3735
onWindowStageDestroy(): void {

entry/src/main/ets/pages/Index.ets

Lines changed: 102 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,112 @@
1+
import { webview } from '@kit.ArkWeb';
2+
import { hilog } from '@kit.PerformanceAnalysisKit';
3+
import napi from 'libentry.so';
4+
5+
const DOMAIN = 0x0001;
6+
7+
interface Size {
8+
width: number,
9+
height: number
10+
}
11+
12+
class NativeProxy {
13+
webviewController: webview.WebviewController
14+
15+
constructor(webviewController: webview.WebviewController) {
16+
this.webviewController = webviewController
17+
}
18+
19+
propUpdate(key: object, value: object): void {
20+
hilog.info(DOMAIN, 'native', '%{public}s', 'propUpdate: ' + key + ", value: " + value);
21+
}
22+
23+
sendInput(data: string): void {
24+
hilog.info(DOMAIN, 'native', '%{public}s', 'sendInput: ' + data);
25+
this.webviewController.runJavaScript('exports.write("' + data + '")')
26+
}
27+
28+
async resize(): Promise<void> {
29+
const s = await this.getSize();
30+
hilog.info(DOMAIN, 'native', '%{public}s', 'resize: ' + s.width + ", " + s.height)
31+
}
32+
33+
focus(): void {
34+
hilog.info(DOMAIN, 'native', '%{public}s', 'focus')
35+
}
36+
37+
syncFocus(): void {
38+
hilog.info(DOMAIN, 'native', '%{public}s', 'syncFocus')
39+
}
40+
41+
newScrollHeight(h: number): void {
42+
hilog.info(DOMAIN, 'native', '%{public}s', 'newScrollHeight: ' + h)
43+
}
44+
45+
newScrollTop(h: number): void {
46+
hilog.info(DOMAIN, 'native', '%{public}s', 'newScrollTop: ' + h)
47+
}
48+
49+
openLink(url: string): void {
50+
hilog.info(DOMAIN, 'native', '%{public}s', 'openLink: ' + url)
51+
}
52+
53+
async load(): Promise<void> {
54+
hilog.info(DOMAIN, 'native', '%{public}s', 'load')
55+
this.webviewController.runJavaScript('exports.write("shell")')
56+
this.webviewController.runJavaScript('exports.setFocused(true)')
57+
58+
const s: Size = await this.getSize();
59+
60+
console.log('w: ' + s.width + ', h: ' + s.height)
61+
}
62+
63+
private async getSize(): Promise<Size> {
64+
const ext = await this.webviewController.runJavaScriptExt('exports.getSize()');
65+
const arr = ext.getArray();
66+
const w = arr[0] as number, h = arr[1] as number;
67+
return { width: w, height: h };
68+
}
69+
}
70+
171
@Entry
272
@Component
373
struct Index {
4-
@State message: string = 'This page is reserved. To use Harmonix, go to HiShell';
74+
webviewController: webview.WebviewController = new webview.WebviewController()
75+
native: NativeProxy = new NativeProxy(this.webviewController);
76+
77+
aboutToAppear(): void {
78+
webview.WebviewController.setWebDebuggingAccess(true)
79+
hilog.info(DOMAIN, 'testTag', 'Test NAPI 2 + 3 = %{public}d', napi.add(2, 3));
80+
}
581

682
build() {
7-
RelativeContainer() {
8-
Text(this.message)
9-
.id('HelloWorld')
10-
.fontSize($r('app.float.page_text_font_size'))
11-
.fontWeight(FontWeight.Normal)
12-
.alignRules({
13-
center: { anchor: '__container__', align: VerticalAlign.Center },
14-
middle: { anchor: '__container__', align: HorizontalAlign.Center }
15-
})
16-
.onClick(() => {
17-
this.message = 'Welcome';
83+
Column() {
84+
Web({
85+
src: $rawfile('term.html'),
86+
controller: this.webviewController
87+
})
88+
.javaScriptProxy({
89+
object: this.native,
90+
name: 'native',
91+
methodList: ['propUpdate', 'sendInput', 'resize', 'focus', 'syncFocus',
92+
'newScrollHeight', 'newScrollTop', 'openLink', 'load', 'syncFocus'],
93+
controller: this.webviewController,
94+
asyncMethodList: [],
95+
permission: `{
96+
"javascriptProxyPermission": {
97+
"urlPermissionList": [
98+
{
99+
"scheme": "resource",
100+
"host": "rawfile",
101+
"port": "",
102+
"path": ""
103+
}
104+
]
105+
}
106+
}`
18107
})
19108
}
20-
.height('100%')
21109
.width('100%')
110+
.height('100%')
22111
}
23112
}

0 commit comments

Comments
 (0)