diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b6215cb83..5ba523c3d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -268,8 +268,6 @@ dependencies { // Android job implementation("com.evernote:android-job:1.4.2") // Optional, if you use support library fragments: - implementation(project(":automator")) - implementation(project(":common")) implementation(project(":autojs")) implementation(project(":apkbuilder")) implementation(project(":codeeditor")) @@ -330,4 +328,9 @@ tasks.register("buildDebugTemplateApp") { doFirst { copyTemplateToAPP(true, assetsDir) } +} +tasks.named("clean").configure { + doFirst { + delete(File(assetsDir, "template.apk")) + } } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/devplugin/DevPlugin.kt b/app/src/main/java/org/autojs/autojs/devplugin/DevPlugin.kt index d6b0206df..8424f895c 100644 --- a/app/src/main/java/org/autojs/autojs/devplugin/DevPlugin.kt +++ b/app/src/main/java/org/autojs/autojs/devplugin/DevPlugin.kt @@ -7,11 +7,26 @@ import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import com.stardust.app.GlobalAppContext -import io.ktor.server.plugins.* -import io.ktor.websocket.* -import kotlinx.coroutines.* +import io.ktor.websocket.CloseReason +import io.ktor.websocket.Frame +import io.ktor.websocket.FrameType +import io.ktor.websocket.WebSocketSession +import io.ktor.websocket.close +import io.ktor.websocket.readBytes +import io.ktor.websocket.readText +import io.ktor.websocket.send +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.ClosedReceiveChannelException -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import okio.ByteString.Companion.toByteString import org.autojs.autojs.devplugin.message.Hello import org.autojs.autojs.devplugin.message.HelloResponse @@ -21,7 +36,6 @@ import org.autojs.autoxjs.BuildConfig import org.autojs.autoxjs.R import java.io.File import java.net.SocketTimeoutException -import java.util.* object DevPlugin { diff --git a/autojs/src/main/assets/modules/npm/rxjs/ext.js b/autojs/src/main/assets/modules/npm/rxjs/ext.js new file mode 100644 index 000000000..84c067286 --- /dev/null +++ b/autojs/src/main/assets/modules/npm/rxjs/ext.js @@ -0,0 +1,191 @@ +let { Subscription, asyncScheduler } = require("./index.js"); +const t = threads; +const mainTimer = timers.mainTimer; +const uiTimer = timers.uiTimer; + +const ioScheduler = { + bid: 0, + schedule(work, delay, state) { + const action = new SchedulerAction(this, work); + return action.schedule(state, delay); + }, + now() { + return Date.now(); + }, + getexecutor() { + return { + id: this.bid++, + th: null, + run(fn, delay) { + if (this.th) { + this.th.setTimeout(fn, delay); + } else { + this.th = t.start(() => { + setTimeout(fn, delay); + }); + } + }, + close() { + this.th.interrupt(); + this.th = null; + //console.log("关闭", this.id); + }, + cancel() { + //console.log("取消", this.id); + }, + }; + }, +}; + +const SchedulerAction = function (scheduler, work) { + Subscription.call(this); + this.work = work; + //this.subAction = []; + this.executor = scheduler.getexecutor(); +}; +SchedulerAction.prototype = Object.create(Subscription.prototype, { + constructor: { value: SchedulerAction }, +}); +Object.assign(SchedulerAction.prototype, { + schedule(state, delay) { + if (this.closed) return new Subscription(); + const call = this.executor.run(() => { + this.work.call(this, state); + }, delay); + const callAction = new Subscription(); + callAction.call = call; + callAction.executor = this.executor; + callAction.unsubscribe = function () { + this.closed = true; + const cancel = this.executor.cancel; + if (cancel) { + cancel.call(this.executor, this.call); + } + }; + return callAction; + }, + unsubscribe() { + this.closed = true; + this.executor.close(); + }, +}); + +const mainScheduler = { + bid: 0, + schedule(work, delay, state) { + const action = new SchedulerAction(this, work); + return action.schedule(state, delay); + }, + now() { + return Date.now(); + }, + getexecutor() { + return { + id: null, + run(fn, delay) { + const id = mainTimer.setTimeout(fn, delay); + return id; + }, + close() { + //console.log("关闭"); + }, + cancel(id) { + mainTimer.clearTimeout(id); + }, + }; + }, +}; + +const uiScheduler = { + bid: 0, + schedule(work, delay, state) { + const action = new SchedulerAction(this, work); + return action.schedule(state, delay); + }, + now() { + return Date.now(); + }, + getexecutor() { + return { + id: null, + run(fn, delay) { + const id = uiTimer.setTimeout(fn, delay); + return id; + }, + close() { + //console.log("关闭"); + }, + cancel(id) { + uiTimer.clearTimeout(id); + }, + }; + }, +}; +const workScheduler = { + bid: 0, + schedule(work, delay, state) { + const action = new SchedulerAction(this, work); + return action.schedule(state, delay); + }, + now() { + return Date.now(); + }, + getexecutor() { + return { + id: null, + run(fn, delay) { + if (delay) { + const id = uiTimer.setTimeout(() => { + t.runTaskForThreadPool(fn); + }, delay); + return id; + } else { + t.runTaskForThreadPool(fn); + return null; + } + }, + close() {}, + cancel(id) { + if (id) uiTimer.clearTimeout(id); + }, + }; + }, +}; +function newSingleScheduler() { + const th = t.start(() => { + setInterval(() => {}, 1000); + }); + th.waitFor(); + return { + th, + bid: 0, + schedule(work, delay, state) { + const action = new SchedulerAction(this, work); + return action.schedule(state, delay); + }, + now() { + return Date.now(); + }, + getexecutor() { + return { + th: this.th, + run(fn, delay) { + return this.th.setTimeout(fn, delay); + }, + close() {}, + cancel(id) { + this.th.clearTimeout(id); + }, + }; + }, + recycle(){ + this.th.interrupt() + } + }; +} + +exports.ioScheduler = ioScheduler; +exports.mainScheduler = mainScheduler; +exports.uiScheduler = uiScheduler; +exports.workScheduler = workScheduler; +exports.newSingleScheduler = newSingleScheduler; diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.kt b/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.kt index 6dec2b03a..a5fdb7d96 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.kt +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.kt @@ -10,7 +10,7 @@ import com.stardust.autojs.runtime.ScriptRuntime */ class Timers(private val mRuntime: ScriptRuntime) { private val mThreads: Threads = mRuntime.threads - private val mUiTimer: Timer = Timer(mRuntime, Looper.getMainLooper()) + val uiTimer: Timer = Timer(mRuntime, Looper.getMainLooper()) val mainTimer get() = mRuntime.loopers.mTimer @@ -23,7 +23,7 @@ class Timers(private val mRuntime: ScriptRuntime) { } val timer = TimerThread.getTimerForThread(thread) return if (timer == null && Looper.myLooper() == Looper.getMainLooper()) { - mUiTimer + uiTimer } else timer ?: mainTimer } diff --git a/build.gradle.kts b/build.gradle.kts index 065bc72ba..c4449f131 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,6 +25,7 @@ buildscript { classpath("com.jakewharton:butterknife-gradle-plugin:10.2.3") classpath("org.codehaus.groovy:groovy-json:3.0.8") classpath("com.yanzhenjie.andserver:plugin:2.1.12") + classpath(libs.okhttp) } } diff --git a/codeeditor/build.gradle.kts b/codeeditor/build.gradle.kts index cea55a4bc..495a65f4f 100644 --- a/codeeditor/build.gradle.kts +++ b/codeeditor/build.gradle.kts @@ -1,4 +1,6 @@ -import java.net.URL +import okhttp3.OkHttpClient +import okhttp3.Request +import okio.use plugins { id("com.android.library") id("kotlin-android") @@ -38,6 +40,7 @@ android { dependencies { implementation(libs.andserver.api) + implementation(libs.androidx.constraintlayout) kapt(libs.andserver.processor) implementation(libs.kotlinx.coroutines.android) api(libs.androidx.webkit) @@ -45,20 +48,17 @@ dependencies { implementation(libs.core.ktx) implementation(libs.androidx.activity.ktx) implementation(libs.appcompat) - implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.5.0") - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0") implementation(libs.material) + implementation(project(":autojs")) testImplementation(libs.junit) androidTestImplementation(libs.androidx.test.ext.junit) - androidTestImplementation(libs.espresso.core){ - exclude(group = "com.android.support",module = "support-annotations") - } + androidTestImplementation(libs.espresso.core) } tasks.register("downloadEditor") { - val tag = "dev-0.3.0" - val version = 3 + val tag = "v0.4.0" + val version = 4 val uri = "https://github.com/aiselp/vscode-mobile/releases/download/${tag}/dist.zip" val assetsDir = File(projectDir, "/src/main/assets/codeeditor") val versionFile = File(assetsDir, "version.txt") @@ -72,7 +72,11 @@ tasks.register("downloadEditor") { return@doFirst } } - URL(uri).openStream().use { + val response = OkHttpClient.Builder().build().newCall( + Request.Builder().url(uri).build() + ).execute() + check(response.isSuccessful){"download error response code:${response.code}"} + response.body!!.byteStream().use { File(assetsDir, "dist.zip").outputStream().use { out-> it.copyTo(out) } diff --git a/codeeditor/src/main/AndroidManifest.xml b/codeeditor/src/main/AndroidManifest.xml index f9517e4b1..a142f3aef 100644 --- a/codeeditor/src/main/AndroidManifest.xml +++ b/codeeditor/src/main/AndroidManifest.xml @@ -5,8 +5,10 @@ diff --git a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/dialogs/LoadDialog.kt b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/dialogs/LoadDialog.kt new file mode 100644 index 000000000..fe87ec930 --- /dev/null +++ b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/dialogs/LoadDialog.kt @@ -0,0 +1,34 @@ +package com.aiselp.autojs.codeeditor.dialogs + +import android.app.Activity +import android.widget.TextView +import androidx.appcompat.app.AlertDialog +import com.aiselp.autojs.codeeditor.R +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class LoadDialog(activity: Activity) { + val dialog: AlertDialog = AlertDialog.Builder( + activity + ) + .setTitle("加载中") + .setView(R.layout.load) + .setCancelable(false) + .create() + val textView: TextView by lazy { + dialog.findViewById(R.id.textView)!! + } + + init { + } + + suspend fun setContent(text: String) { + withContext(Dispatchers.Main) { + textView.text = text + } + } + + fun show() { + dialog.show() + } +} \ No newline at end of file diff --git a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/plugins/AppController.kt b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/plugins/AppController.kt new file mode 100644 index 000000000..5728d990e --- /dev/null +++ b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/plugins/AppController.kt @@ -0,0 +1,80 @@ +package com.aiselp.autojs.codeeditor.plugins + +import android.app.Activity +import android.os.Build +import android.widget.Toast +import androidx.annotation.RequiresApi +import com.aiselp.autojs.codeeditor.web.PluginManager +import com.aiselp.autojs.codeeditor.web.annotation.WebFunction +import com.stardust.app.GlobalAppContext +import com.stardust.autojs.AutoJs +import com.stardust.autojs.execution.ExecutionConfig +import com.stardust.autojs.execution.ScriptExecution +import com.stardust.autojs.execution.ScriptExecutionListener +import com.stardust.autojs.execution.ScriptExecutionTask +import com.stardust.autojs.script.ScriptSource +import com.stardust.autojs.script.StringScriptSource +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch + +@RequiresApi(Build.VERSION_CODES.M) + +class AppController(val activity: Activity) { + companion object { + const val TAG = "AppController" + } + + private val autojs: AutoJs? = try { + val cz = Class.forName("org.autojs.autojs.autojs.AutoJs") + val obj = cz.getMethod("getInstance").invoke(null) + obj as? AutoJs + } catch (e: Exception) { + null + } + + @WebFunction + fun exit(call: PluginManager.WebCall) { + call.onSuccess(null) + activity.finish() + } + + @OptIn(DelicateCoroutinesApi::class) + @WebFunction + fun back(call: PluginManager.WebCall) { + call.onSuccess(null) + GlobalScope.launch(Dispatchers.Main) { + activity.moveTaskToBack(false) + } + } + + @WebFunction + fun runScript(call: PluginManager.WebCall) { + val path = FileSystem.parsePath(call.data!!) + val file: ScriptSource = StringScriptSource(path.name, path.readText()) + try { + autojs?.let { + it.scriptEngineService.execute( + ScriptExecutionTask(file, object : + ScriptExecutionListener { + override fun onStart(execution: ScriptExecution?) {} + + override fun onSuccess(execution: ScriptExecution?, result: Any?) { + call.onSuccess(null) + } + + override fun onException(execution: ScriptExecution?, e: Throwable?) { + call.onError(Exception(e)) + } + + }, ExecutionConfig(workingDirectory = path.parent ?: "/")) + ) + } ?: call.onError(Exception("没有运行接口")) + } catch (e: Exception) { + e.printStackTrace() + Toast.makeText(GlobalAppContext.get(), e.message, Toast.LENGTH_LONG).show() + call.onError(e) + } + } +} \ No newline at end of file diff --git a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/plugins/FileSystem.kt b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/plugins/FileSystem.kt index f188ab1c4..03f340e4f 100644 --- a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/plugins/FileSystem.kt +++ b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/plugins/FileSystem.kt @@ -1,5 +1,6 @@ package com.aiselp.autojs.codeeditor.plugins +import android.content.Context import android.os.Build import android.os.Environment import android.util.Base64 @@ -11,18 +12,36 @@ import com.google.gson.Gson import java.io.File @RequiresApi(Build.VERSION_CODES.M) -class FileSystem() { +class FileSystem(context: Context) { companion object { const val TAG = "FileSystem" const val MaxFileSize = 1024 * 1024 * 5 - val basePath: File = Environment.getExternalStorageDirectory() + private val basePath: File = Environment.getExternalStorageDirectory() + private var sampleDir: File? = null + private const val sampleBase = "/_-__sample__-_" + fun parsePath(path: String): File { + if (path.startsWith(sampleBase)) { + return File(sampleDir, path.replace(sampleBase, "")) + } + return File(basePath, path) + } + + fun toWebPath(path: File): String { + if (path.path.startsWith(basePath.path)) { + return path.path.replace(basePath.path, "") + } + val samplePath = sampleDir?.path + if (samplePath != null && path.path.startsWith(samplePath)) { + return sampleBase + path.path.replace(samplePath, "") + } + return path.path + } } private val gson = Gson() - private fun parsePath(path: String?): File { - check(path != null) { "path is null" } - return File(basePath, path) + init { + sampleDir = File(context.filesDir, "sample") } @WebFunction diff --git a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/EditorAppManager.kt b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/EditorAppManager.kt index d2dd57d4b..3ef66abe8 100644 --- a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/EditorAppManager.kt +++ b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/EditorAppManager.kt @@ -7,18 +7,17 @@ import android.util.Log import android.view.ViewGroup import android.webkit.WebView import androidx.annotation.RequiresApi +import com.aiselp.autojs.codeeditor.dialogs.LoadDialog +import com.aiselp.autojs.codeeditor.plugins.AppController import com.aiselp.autojs.codeeditor.plugins.FileSystem +import com.stardust.pio.PFiles import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.async import kotlinx.coroutines.cancel -import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors import java.util.zip.ZipEntry import java.util.zip.ZipInputStream @@ -27,11 +26,11 @@ class EditorAppManager(val context: Activity) { companion object { const val TAG = "EditorAppManager" const val WEB_DIST_PATH = "codeeditor/dist.zip" + const val VERSION_FILE = "codeeditor/version.txt" const val WEB_PUBLIC_PATH = "editorWeb/" } private val coroutineScope = CoroutineScope(Dispatchers.Default) - private val executors: ExecutorService = Executors.newSingleThreadExecutor() val webView = createWebView(context) private val jsBridge = JsBridge(webView) private val fileHttpServer = FileHttpServer( @@ -41,21 +40,26 @@ class EditorAppManager(val context: Activity) { ) private val pluginManager = PluginManager(jsBridge, coroutineScope) var opendeFile: String? = null + private val loadDialog = LoadDialog(context) init { webView.webViewClient = JsBridge.SuperWebViewClient() installPlugin() + loadDialog.show() coroutineScope.launch { - launch(executors.asCoroutineDispatcher()) { fileHttpServer.start() } + fileHttpServer.start() async { initWebResources() }.await() - delay(300) + loadDialog.setContent("启动中") + fileHttpServer.await() withContext(Dispatchers.Main) { webView.loadUrl(fileHttpServer.getAddress()) -// webView.loadUrl("http://192.168.10.10:8009") +// webView.loadUrl("http://192.168.10.10:8010") + loadDialog.dialog.dismiss() } } // webView.loadUrl("http://appassets.androidplatform.net/index.html") jsBridge.registerHandler("app.init", JsBridge.Handle { _, _ -> + pluginManager.onWebInit() val file = opendeFile if (file != null) { openFile(file) @@ -64,21 +68,20 @@ class EditorAppManager(val context: Activity) { } private fun installPlugin() { - pluginManager.registerPlugin("FileSystem", FileSystem()) - jsBridge.registerHandler("app.exitApp", JsBridge.Handle { _, _ -> - coroutineScope.launch(Dispatchers.Main) { - context.moveTaskToBack(false) - } - }) + pluginManager.registerPlugin(FileSystem.TAG, FileSystem(context)) + pluginManager.registerPlugin(AppController.TAG, AppController(context)) } - private fun initWebResources() { + private suspend fun initWebResources() { val webDir = File(context.filesDir, WEB_PUBLIC_PATH) val versionFile = File(webDir, "version.txt") if (isUpdate(versionFile)) { Log.i(TAG, "skip initWebResources") return } + if (PFiles.deleteRecursively(webDir)) { + loadDialog.setContent("正在更新") + } else loadDialog.setContent("正在安装") Log.i(TAG, "initWebResources") webDir.mkdirs() context.assets.open(WEB_DIST_PATH).use { it -> @@ -99,17 +102,16 @@ class EditorAppManager(val context: Activity) { } } } - val versionCode = context.packageManager.getPackageInfo(context.packageName, 0).versionCode - versionFile.writeText(versionCode.toString()) + val versionCode = String(context.assets.open(VERSION_FILE).use { it.readBytes() }) + versionFile.writeText(versionCode) } private fun isUpdate(file: File): Boolean { if (!file.isFile) return false return try { val text = file.readText().toLong() - val versionCode = - context.packageManager.getPackageInfo(context.packageName, 0).versionCode - versionCode.toLong() == text + val versionCode = context.assets.open(VERSION_FILE).use { it.readBytes() } + String(versionCode).toLong() == text } catch (e: Exception) { false } @@ -119,11 +121,10 @@ class EditorAppManager(val context: Activity) { webView.destroy() fileHttpServer.stop() coroutineScope.cancel() - executors.shutdownNow() } fun openFile(path: String) { - jsBridge.callHandler("app.openFile", path.replace(FileSystem.basePath.path, ""), null) + jsBridge.callHandler("app.openFile", FileSystem.toWebPath(File(path)), null) } fun onKeyboardDidShow() { diff --git a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/FileHttpServer.kt b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/FileHttpServer.kt index c4592caf3..62ab49fa8 100644 --- a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/FileHttpServer.kt +++ b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/FileHttpServer.kt @@ -6,9 +6,11 @@ import android.util.Log import androidx.annotation.RequiresApi import com.yanzhenjie.andserver.AndServer import com.yanzhenjie.andserver.Server +import com.yanzhenjie.andserver.Server.ServerListener import com.yanzhenjie.andserver.annotation.Config import com.yanzhenjie.andserver.framework.config.WebConfig import com.yanzhenjie.andserver.framework.website.StorageWebsite +import kotlinx.coroutines.CompletableDeferred import java.io.File import java.io.IOException import java.net.ServerSocket @@ -18,6 +20,7 @@ import kotlin.random.Random class FileHttpServer(context: Context, path: File) { companion object { + private const val Tag = "FileHttpServer" fun isPortAvailable(port: Int): Boolean { try { ServerSocket(port).use { @@ -30,9 +33,20 @@ class FileHttpServer(context: Context, path: File) { } private val port = getPort() + private val status = CompletableDeferred() val server: Server = AndServer.webServer(context) .port(port) .timeout(10, TimeUnit.SECONDS) + .listener(object : ServerListener { + override fun onStarted() { + status.complete(true) + } + + override fun onStopped() {} + override fun onException(e: Exception?) { + status.completeExceptionally(e ?: Exception("$Tag start fail")) + } + }) .build(); private fun getPort(): Int { @@ -43,14 +57,21 @@ class FileHttpServer(context: Context, path: File) { } } } + fun getAddress(): String { return "http://127.0.0.1:$port" } - fun start(){ - Log.d("FileHttpServer", "FileHttpServer init host: 127.0.0.1 port: $port") + + fun start() { + Log.d(Tag, "FileHttpServer init host: 127.0.0.1 port: $port") server.startup() } - fun stop(){ + + suspend fun await() { + status.await() + } + + fun stop() { server.shutdown() } } diff --git a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/PluginManager.kt b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/PluginManager.kt index 93a5c7fbe..0f4941e5e 100644 --- a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/PluginManager.kt +++ b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/PluginManager.kt @@ -54,14 +54,18 @@ class PluginManager(private val jsBridge: JsBridge, private val coroutineScope: coroutineScope.launch { try { method.invoke(plugin.plugin, webCall) - }catch (e: Exception) { + } catch (e: Exception) { Log.e(TAG, "web call method:${call.method} error") - Log.e(TAG, e.toString()) + e.printStackTrace() webCall.onError(e) } } } + fun onWebInit() = coroutineScope.launch { + + } + fun registerPlugin(id: String, plugin: Any) { pluginMap[id] = WebPlugin(id, plugin) diff --git a/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/WebEvent.kt b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/WebEvent.kt new file mode 100644 index 000000000..1b5b05e12 --- /dev/null +++ b/codeeditor/src/main/java/com/aiselp/autojs/codeeditor/web/WebEvent.kt @@ -0,0 +1,4 @@ +package com.aiselp.autojs.codeeditor.web + +class WebEvent() { +} \ No newline at end of file diff --git a/codeeditor/src/main/res/layout/load.xml b/codeeditor/src/main/res/layout/load.xml new file mode 100644 index 000000000..421c7d483 --- /dev/null +++ b/codeeditor/src/main/res/layout/load.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 593cfa979..ba1d96e8b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,6 +24,11 @@ compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", versio compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose-version" } compose-material = { module = "androidx.compose.material:material", version.ref = "compose-version" } compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose-version" } +#compose-bom = "androidx.compose:compose-bom:2023.03.00" +compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose-version" } +compose-foundation-layout = { module = "androidx.compose.foundation:foundation-layout", version.ref = "compose-version" } +compose-animation-core = { module = "androidx.compose.animation:animation-core", version.ref = "compose-version" } +compose-animation = { module = "androidx.compose.animation:animation", version.ref = "compose-version" } # accompanist accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist-version" } accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist-version" } @@ -61,6 +66,7 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a material = { group = "com.google.android.material", name = "material", version.ref = "material" } andserver-processor = { module = "com.yanzhenjie.andserver:processor", version.ref = "andserver" } andserver-api = { module = "com.yanzhenjie.andserver:api", version.ref = "andserver" } +androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version = "2.1.4" } [plugins] [bundles]