diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletHostActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletHostActivity.kt index 118a8ede24..9e641973a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletHostActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletHostActivity.kt @@ -48,7 +48,6 @@ import com.vitorpamplona.amethyst.commons.napplet.NappletWebContract import com.vitorpamplona.amethyst.commons.napplet.protocol.NappletProtocolJson import com.vitorpamplona.amethyst.commons.napplet.resolveRequiredCapabilities import com.vitorpamplona.quartz.nip5aStaticWebsites.tags.PathTag -import kotlinx.coroutines.runBlocking import org.json.JSONObject /** @@ -130,7 +129,12 @@ class NappletHostActivity : ComponentActivity() { // The shell page + shim are the shared web contract (commons composeResources); load them // once up front so the WebView worker threads that serve them never block on resource I/O. - val (shellHtml, shim) = runBlocking { NappletWebContract.shellHtml() to NappletWebContract.shimJs().decodeToString() } + // This isolated `:napplet` process skips app init (to stay key-free), so the compose-resources + // Android context is never set here and `Res.readBytes` would crash — read the contract bytes + // straight from the APK assets, where compose-resources packages them. + fun readContractAsset(path: String): ByteArray = assets.open(NappletWebContract.RESOURCE_ASSET_ROOT + path).use { it.readBytes() } + val shellHtml = readContractAsset(NappletWebContract.SHELL_HTML_PATH) + val shim = readContractAsset(NappletWebContract.SHIM_JS_PATH).decodeToString() contentServer = NappletContentServer(paths, servers, proxyPort, cacheDir, shellHtml, shim) webView = WebView(this) diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletWebContract.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletWebContract.kt index cde595faf1..7b85ccdaea 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletWebContract.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletWebContract.kt @@ -68,8 +68,17 @@ object NappletWebContract { "media-src 'self' https://napplet.local blob: data:; " + "connect-src 'none'; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'none'" - private const val SHELL_HTML_PATH = "files/napplet/shell.html" - private const val SHIM_JS_PATH = "files/napplet/shim.js" + const val SHELL_HTML_PATH = "files/napplet/shell.html" + const val SHIM_JS_PATH = "files/napplet/shim.js" + + /** + * Asset directory the compose-resources of `:commons` are packaged under on Android (mirrors the + * prefix the generated [Res] accessor prepends). Hosts that run in a process without an + * initialized compose-resources context — e.g. the isolated `:napplet` process, which skips app + * init to stay key-free — read [SHELL_HTML_PATH]/[SHIM_JS_PATH] straight from `assets` under this + * root instead of going through [shellHtml]/[shimJs]. + */ + const val RESOURCE_ASSET_ROOT = "composeResources/com.vitorpamplona.amethyst.commons.resources/" /** The trusted shell page's HTML, read from the shared bundle. */ @OptIn(ExperimentalResourceApi::class)