![](/img/trans.png)
[英]Android webView evaluateJavaScript executes undefined function
[英]Creating a queue for the evaluateJavascript function on a WebView
我有一個混合應用程序,我的一些活動使用 WebView 來顯示 web 內容。 我在 WebView 中展示的 web 應用程序有一個 JS 接口,可以讓我向 web 應用程序發送命令以導航到不同的地方或做不同的事情。
例如,如果我需要我的 web 應用程序導航到“用戶配置文件”頁面,我執行如下命令:
class SomeActivity: AppCompatActivity {
...
webView.evaluateJavascript("navigateTo(\"userprofile\")")
...
}
然后通過 JS 界面,我得到一個響應,應用程序做出相應的反應。
為了提高性能,我引入了一個 JS 隊列,因此 JS 命令是按順序執行的。 我沒有直接在 WebView 上調用evaluateJavascript()
function,而是創建了一個自定義 WebView 組件,並將此 JS 隊列設置為屬性。
class SomeActivity: AppCompatActivity {
...
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"userprofile\")")
...
}
現在我想在此之上添加一個新行為,那就是能夠預處理隊列中的命令。 我所說的預處理的意思是,如果我曾經對相同“類型”的命令進行排隊,例如:
class SomeActivity: AppCompatActivity {
...
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"userprofile\")")
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"about-me\")")
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"user-list\")")
...
}
我想要發生的是隊列足夠聰明,可以放棄這兩個第一個“導航”命令 - "navigateTo(\"userprofile\")"
和"navigateTo(\"about-me\")"
- 因為我不'不希望我的 WebView 導航到這兩個地方只是為了最終導航到"navigateTo(\"user-list\")"
。
這個 JS 隊列的實現是這樣的:
class JsQueue(
private val webView: WebView,
private val scope: CoroutineScope
) {
init {
scope.launch {
for (jsScript in jsChannel) {
runJs(jsScript)
}
}
}
private val jsChannel = Channel<String>(BUFFERED)
fun queueEvaluateJavascript(script: String) {
runBlocking {
jsChannel.send(script)
}
}
suspend fun runJs(script: String) = suspendCoroutine<String> { cont ->
webView.evaluateJavascript(script) { result ->
cont.resume(result)
}
}
}
Channel<String>
中的 js 命令,以便放棄重復的 js 命令?編輯#1
此外,有時我的 WebView 會變得不可見,我想在發生這種情況時暫停隊列。 我想知道是否有任何方法可以以編程方式暫停Channel ?
我試過使用這個PausableDispatcher
實現,它似乎在做這個伎倆。
您提供的所有命令示例都遵循特定模式:它們都是函數。 我們可以利用這個優勢!
首先,讓我們創建一些術語。
navigateTo()
是一個 function (當然。)。 讓我們將 function 的navigateTo
部分稱為type
。
一些type
的例子是:
console.log() => `console.log`,
gotoUrl(url) => `gotoUrl`.
我只是編造了這個術語。 但它會幫助你理解邏輯。
現在,我們需要做的是查看命令數組,了解它的type
,並檢查是否有其他命令具有相同的類型。 如果是這樣,則需要在執行隊列之前將它們從隊列中排除。
簡單的!
我編寫了一個示例代碼,您可以將其與您的腳本集成:
// Example array of commands for demonstration.
let commands = [
'navigateTo("a")',
'navigateTo("b")',
'navigateTo("c")',
];
/** A list of non-duplicate types*/
let types = [];
/** A list of non-duplicate commands */
let newCommands = [];
// Reverse the array because the most important commands start from the end of array.
for(let command of commands.reverse()){
let type = command.slice(0, command.indexOf('('));
// Determine if type already exists
let alreadyExists = false;
for(let commandType of types){
if(type == commandType){
alreadyExists = true;
break;
}
}
if(alreadyExists)
// Type already exists. Do not add to command list.
continue;
// This type & command does not exist.
// Update command & type arrays
types.push(type);
newCommands.push(command)
}
// New Commands
console.log("Commands: ", newCommands);
// If you want to keep same queue order without duplicates:
console.log("Commands: ", newCommands.reverse())
如果我錯過了回答這個問題的分數,請告訴我。 否則,為一個偉大的隊列系統干杯!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.