Skip to content

Commit

Permalink
Android URL pathname resolver (#690)
Browse files Browse the repository at this point in the history
Co-authored-by: Bret Comnes <[email protected]>
  • Loading branch information
jwerle and bcomnes authored Oct 12, 2023
1 parent d929e9a commit fdbf0b2
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 15 deletions.
5 changes: 0 additions & 5 deletions src/android/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ open class MainActivity : WebViewActivity() {
}
}

fun getRootDirectory (): String {
return getExternalFilesDir(null)?.absolutePath
?: "/sdcard/Android/data/__BUNDLE_IDENTIFIER__/files"
}

fun checkPermission (permission: String): Boolean {
val status = androidx.core.content.ContextCompat.checkSelfPermission(
this.applicationContext,
Expand Down
93 changes: 84 additions & 9 deletions src/android/webview.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ open class WebChromeClient (activity: MainActivity) : android.webkit.WebChromeCl
}
}

final class WebViewURLPathResolution (path: String, redirect: Boolean = false) {
val path = path
val redirect = redirect
}

/**
* @see https://developer.android.com/reference/kotlin/android/webkit/WebViewClient
*/
Expand Down Expand Up @@ -140,6 +145,67 @@ open class WebViewClient (activity: WebViewActivity) : android.webkit.WebViewCli
return true
}

fun resolveURLPathForWebView (input: String? = null): WebViewURLPathResolution? {
var path = input ?: return null
val activity = this.activity.get() ?: return null
val assetManager = activity.getAssetManager() ?: return null
val root = activity.getRootDirectory()

if (path == "/") {
try {
val htmlPath = "index.html"
val stream = assetManager.open(htmlPath)
stream.close()
return WebViewURLPathResolution("/" + htmlPath)
} catch (_: Exception) {}
}

if (path.startsWith("/")) {
path = path.substring(1, path.length)
} else if (path.startsWith("./")) {
path = path.substring(2, path.length)
}

try {
val htmlPath = path
val stream = assetManager.open(htmlPath)
stream.close()
return WebViewURLPathResolution("/" + htmlPath)
} catch (_: Exception) {}

if (path.endsWith("/")) {
try {
val list = assetManager.list(path)
if (list != null && list.size > 0) {
try {
val htmlPath = path + "index.html"
val stream = assetManager.open(htmlPath)
stream.close()
return WebViewURLPathResolution("/" + htmlPath)
} catch (_: Exception) {}
}
} catch (_: Exception) {}

return null
} else {
try {
val htmlPath = path + "/index.html"
val stream = assetManager.open(htmlPath)
stream.close()
return WebViewURLPathResolution("/" + htmlPath, true)
} catch (_: Exception) {}
}

try {
val htmlPath = path + ".html"
val stream = assetManager.open(htmlPath)
stream.close()
return WebViewURLPathResolution("/" + htmlPath)
} catch (_: Exception) {}

return null
}

override fun shouldInterceptRequest (
view: android.webkit.WebView,
request: android.webkit.WebResourceRequest
Expand All @@ -156,18 +222,18 @@ open class WebViewClient (activity: WebViewActivity) : android.webkit.WebViewCli
var path = url.path
val regex = Regex("(\\.[a-z|A-Z|0-9|_|-]+)$")
var redirect = false
val resolved = resolveURLPathForWebView(path)

if (path != null && !regex.containsMatchIn(path)) {
if (path.endsWith("/")) {
path += "index.html"
} else {
path += "/"
redirect = true
}
if (resolved != null) {
path = resolved.path
}

if (redirect) {
val redirectURL = "${url.scheme}://${url.host}${path}"
if (resolved != null && resolved.redirect) {
redirect = true
}

if (redirect && resolved != null) {
val redirectURL = "${url.scheme}://${url.host}${resolved.path}"
val redirectSource = """
<meta http-equiv="refresh" content="0; url='${redirectURL}'" />"
"""
Expand Down Expand Up @@ -385,6 +451,15 @@ open class WebViewActivity : androidx.appcompat.app.AppCompatActivity() {
}
}

fun getAssetManager (): android.content.res.AssetManager {
return this.applicationContext.resources.assets
}

open fun getRootDirectory (): String {
return getExternalFilesDir(null)?.absolutePath
?: "/sdcard/Android/data/__BUNDLE_IDENTIFIER__/files"
}

/**
* Called when the `WebViewActivity` is first created
* @see https://developer.android.com/reference/kotlin/android/app/Activity#onCreate(android.os.Bundle)
Expand Down
1 change: 0 additions & 1 deletion src/window/win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,6 @@ namespace SSC {
path = userConfig["webview_default_index"];
} else if (resolved.redirect) {
uri += "/";
app.dispatch([&, uri, path, args, deferral, env] {
ICoreWebView2WebResourceResponse* res = nullptr;
env->CreateWebResourceResponse(
nullptr,
Expand Down

0 comments on commit fdbf0b2

Please sign in to comment.