mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-09 12:32:30 +01:00
Install background message handler once
This commit is contained in:
parent
dc3126b622
commit
240dc864e1
@ -25,6 +25,7 @@ import com.pitchedapps.frost.db.FrostDb
|
||||
import com.pitchedapps.frost.ext.FrostAccountId
|
||||
import com.pitchedapps.frost.ext.idData
|
||||
import com.pitchedapps.frost.ext.launchActivity
|
||||
import com.pitchedapps.frost.extension.FrostCoreExtension
|
||||
import com.pitchedapps.frost.main.MainActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
@ -45,8 +46,8 @@ import kotlinx.coroutines.withContext
|
||||
class StartActivity : AppCompatActivity(), CoroutineScope by MainScope() {
|
||||
|
||||
@Inject lateinit var frostDb: FrostDb
|
||||
|
||||
@Inject lateinit var dataStore: FrostDataStore
|
||||
@Inject lateinit var frostCoreExtension: FrostCoreExtension
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -54,7 +55,9 @@ class StartActivity : AppCompatActivity(), CoroutineScope by MainScope() {
|
||||
launch {
|
||||
val id = withContext(Dispatchers.IO) { getCurrentAccountId() }
|
||||
|
||||
logger.atInfo().log("Starting Frost with id %d", id)
|
||||
frostCoreExtension.install()
|
||||
|
||||
logger.atInfo().log("Starting Frost with id %s", id)
|
||||
|
||||
launchActivity<MainActivity>(
|
||||
intentBuilder = {
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 Allan Wang
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.pitchedapps.frost.compose
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.pitchedapps.frost.ext.components
|
||||
import com.pitchedapps.frost.extension.FrostCoreExtension
|
||||
|
||||
/** Disposable effect to attack [FrostCoreExtension]. */
|
||||
@Composable
|
||||
fun FrostCoreExtensionEffect() {
|
||||
val components = LocalContext.current.components
|
||||
|
||||
DisposableEffect(components.core.store) {
|
||||
val feature =
|
||||
FrostCoreExtension(
|
||||
runtime = components.core.engine,
|
||||
store = components.core.store,
|
||||
converter = components.extensionModelConverter,
|
||||
)
|
||||
|
||||
feature.start()
|
||||
|
||||
onDispose { feature.stop() }
|
||||
}
|
||||
}
|
@ -16,18 +16,18 @@
|
||||
*/
|
||||
package com.pitchedapps.frost.extension
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.google.common.flogger.FluentLogger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import mozilla.components.browser.state.selector.findCustomTabOrSelectedTab
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.concept.engine.EngineSession
|
||||
import mozilla.components.concept.engine.webextension.MessageHandler
|
||||
import mozilla.components.concept.engine.webextension.Port
|
||||
import mozilla.components.concept.engine.webextension.WebExtensionRuntime
|
||||
import mozilla.components.lib.state.ext.flowScoped
|
||||
import mozilla.components.support.base.feature.LifecycleAwareFeature
|
||||
import mozilla.components.lib.state.ext.flow
|
||||
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged
|
||||
import mozilla.components.support.webextensions.WebExtensionController
|
||||
import org.json.JSONObject
|
||||
@ -39,49 +39,56 @@ import org.json.JSONObject
|
||||
*
|
||||
* https://github.com/mozilla-mobile/android-components/blob/main/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FxaWebChannelFeature.kt
|
||||
*/
|
||||
class FrostCoreExtension(
|
||||
private val customTabSessionId: String? = null,
|
||||
private val runtime: WebExtensionRuntime,
|
||||
@Singleton
|
||||
class FrostCoreExtension
|
||||
@Inject
|
||||
internal constructor(
|
||||
private val engine: Engine,
|
||||
private val store: BrowserStore,
|
||||
private val converter: ExtensionModelConverter,
|
||||
) : LifecycleAwareFeature {
|
||||
) {
|
||||
|
||||
private val extensionController =
|
||||
WebExtensionController(
|
||||
WEB_CHANNEL_EXTENSION_ID,
|
||||
WEB_CHANNEL_EXTENSION_URL,
|
||||
WEB_CHANNEL_MESSAGING_ID
|
||||
WEB_CHANNEL_MESSAGING_ID,
|
||||
)
|
||||
|
||||
private var scope: CoroutineScope? = null
|
||||
|
||||
override fun start() {
|
||||
logger.atInfo().log("start")
|
||||
fun install() {
|
||||
logger.atInfo().log("extension background start")
|
||||
val messageHandler = FrostBackgroundMessageHandler()
|
||||
extensionController.registerBackgroundMessageHandler(
|
||||
messageHandler,
|
||||
WEB_CHANNEL_BACKGROUND_MESSAGING_ID,
|
||||
)
|
||||
|
||||
extensionController.install(runtime)
|
||||
|
||||
scope =
|
||||
store.flowScoped { flow ->
|
||||
flow
|
||||
.mapNotNull { state -> state.findCustomTabOrSelectedTab(customTabSessionId) }
|
||||
.ifChanged { it.engineState.engineSession }
|
||||
.collect {
|
||||
it.engineState.engineSession?.let { engineSession ->
|
||||
logger.atInfo().log("Register content message handler ${it.id}")
|
||||
registerContentMessageHandler(engineSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
extensionController.install(
|
||||
engine,
|
||||
onSuccess = {
|
||||
logger.atInfo().log("extension install success")
|
||||
extensionController.sendBackgroundMessage(
|
||||
JSONObject().apply { put("test", 0) },
|
||||
WEB_CHANNEL_BACKGROUND_MESSAGING_ID
|
||||
)
|
||||
},
|
||||
onError = { t -> logger.atWarning().withCause(t).log("extension install failure") },
|
||||
)
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
logger.atInfo().log("stop")
|
||||
scope?.cancel()
|
||||
suspend fun installContent(owner: LifecycleOwner? = null, customTabSessionId: String? = null) {
|
||||
logger.atInfo().log("extension content start")
|
||||
|
||||
store
|
||||
.flow(owner)
|
||||
.mapNotNull { state -> state.findCustomTabOrSelectedTab(customTabSessionId) }
|
||||
.ifChanged { it.engineState.engineSession }
|
||||
.collect {
|
||||
it.engineState.engineSession?.let { engineSession ->
|
||||
logger.atInfo().log("Register content message handler ${it.id}")
|
||||
registerContentMessageHandler(engineSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerContentMessageHandler(engineSession: EngineSession) {
|
||||
|
@ -154,7 +154,7 @@ object FrostModule {
|
||||
if (action is EngineAction.LoadUrlAction) {
|
||||
logger.atInfo().log("BrowserAction: LoadUrlAction %s", action.url)
|
||||
} else {
|
||||
logger.atFine().log("BrowserAction: %s - %s", action::class.simpleName, action)
|
||||
logger.atInfo().log("BrowserAction: %s - %s", action::class.simpleName, action)
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
|
@ -22,9 +22,12 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@ -35,12 +38,26 @@ import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.pitchedapps.frost.compose.FrostCoreExtensionEffect
|
||||
import com.pitchedapps.frost.compose.FrostWeb
|
||||
import com.pitchedapps.frost.ext.GeckoContextId
|
||||
import com.pitchedapps.frost.ext.components
|
||||
import mozilla.components.browser.state.helper.Target
|
||||
|
||||
@Composable
|
||||
fun MainScreen2(modifier: Modifier) {
|
||||
// Scaffold(
|
||||
// modifier = modifier,
|
||||
// topBar = {
|
||||
// MainTopBar(modifier = modifier)
|
||||
// },
|
||||
// )
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MainTopBar(modifier: Modifier) {
|
||||
// TopAppBar(title = { /*TODO*/ })
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen for MainActivity.
|
||||
*
|
||||
@ -53,9 +70,10 @@ fun MainScreen(modifier: Modifier = Modifier, tabs: List<MainTabItem>) {
|
||||
|
||||
if (tabs.isEmpty()) return // not ready
|
||||
|
||||
// val contextId = GeckoContextId("test-context")
|
||||
val contextId = vm.contextIdFlow.collectAsState(initial = null).value ?: return // not ready
|
||||
|
||||
FrostCoreExtensionEffect()
|
||||
LaunchedEffect(vm) { vm.frostCoreExtension.installContent() }
|
||||
|
||||
val onTabSelect =
|
||||
remember(vm) {
|
||||
@ -95,9 +113,12 @@ private fun MainContainer(
|
||||
}
|
||||
|
||||
Column(modifier = modifier) {
|
||||
MainHeader(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
title = tabs.getOrNull(tabIndex)?.title ?: "",
|
||||
)
|
||||
if (tabs.size > 1) {
|
||||
MainTabRow(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
selectedIndex = tabIndex,
|
||||
items = tabs,
|
||||
onTabSelect = onTabSelect,
|
||||
@ -113,6 +134,18 @@ private fun MainContainer(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MainHeader(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TopAppBar(
|
||||
modifier = modifier,
|
||||
title = { Text(text = title) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MainTabRow(
|
||||
selectedIndex: Int,
|
||||
|
@ -24,6 +24,7 @@ import androidx.lifecycle.ViewModel
|
||||
import com.pitchedapps.frost.ext.GeckoContextId
|
||||
import com.pitchedapps.frost.ext.idData
|
||||
import com.pitchedapps.frost.ext.toContextId
|
||||
import com.pitchedapps.frost.extension.FrostCoreExtension
|
||||
import com.pitchedapps.frost.hilt.FrostComponents
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
@ -37,6 +38,7 @@ class MainScreenViewModel
|
||||
internal constructor(
|
||||
@ApplicationContext context: Context,
|
||||
val components: FrostComponents,
|
||||
val frostCoreExtension: FrostCoreExtension,
|
||||
) : ViewModel() {
|
||||
|
||||
val contextIdFlow: Flow<GeckoContextId?> =
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"manifest_version": 2,
|
||||
"name": "frostcore",
|
||||
"version": "1.0.0",
|
||||
"description": "Core web extension for Frost",
|
||||
@ -8,9 +8,6 @@
|
||||
"id": "frost_gecko_core@pitchedapps"
|
||||
}
|
||||
},
|
||||
"host_permissions": [
|
||||
"*://*/*"
|
||||
],
|
||||
"background": {
|
||||
"scripts": [
|
||||
"js/background/cookies.js"
|
||||
@ -35,10 +32,17 @@
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"<all_urls>",
|
||||
"activeTab",
|
||||
"contextMenus",
|
||||
"contextualIdentities",
|
||||
"cookies",
|
||||
"history",
|
||||
"management",
|
||||
"tabs",
|
||||
"nativeMessaging",
|
||||
"nativeMessagingFromContent",
|
||||
"geckoViewAddons"
|
||||
"geckoViewAddons",
|
||||
"webRequest"
|
||||
]
|
||||
}
|
@ -3,15 +3,42 @@ async function updateCookies(changeInfo: browser.cookies._OnChangedChangeInfo) {
|
||||
const application = "frostBackgroundChannel"
|
||||
|
||||
browser.runtime.sendNativeMessage(application, changeInfo)
|
||||
}
|
||||
|
||||
return
|
||||
async function readCookies() {
|
||||
const application = "frostBackgroundChannel"
|
||||
|
||||
browser.runtime.sendNativeMessage(application, 'start cookie fetch for')
|
||||
browser.runtime.sendNativeMessage(application, 'start cookie fetch')
|
||||
|
||||
// Testing with domains or urls didn't work
|
||||
const cookies = await browser.cookies.getAll({});
|
||||
|
||||
browser.runtime.sendNativeMessage(application, cookies)
|
||||
const cookies2 = await browser.cookies.getAll({ storeId: "firefox-container-frost-context-1" })
|
||||
|
||||
const cookieStores = await browser.cookies.getAllCookieStores();
|
||||
|
||||
browser.runtime.sendNativeMessage(application, { name: "cookies", data: cookies.length, stores: cookieStores.map((s) => s.id), data2: cookies2.length, data3: cookies.filter(s => s.storeId != 'firefox-default').length })
|
||||
}
|
||||
|
||||
browser.cookies.onChanged.addListener(updateCookies);
|
||||
async function handleMessage(request: any, sender: browser.runtime.MessageSender, sendResponse: (response?: any) => void) {
|
||||
browser.runtime.sendNativeMessage("frostBackgroundChannel", 'pre send')
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
browser.runtime.sendNativeMessage("frostBackgroundChannel", 'post send')
|
||||
|
||||
sendResponse({ received: request, asdf: "asdf" })
|
||||
}
|
||||
|
||||
// Reading cookies with storeId might not be fully supported on Android
|
||||
// https://stackoverflow.com/q/76505000/4407321
|
||||
// Using manifest 3 stopped getAll from working
|
||||
// Reading now always shows storeId as firefox-default
|
||||
// Setting a cookie with a custom container does not seem to work
|
||||
|
||||
// browser.cookies.onChanged.addListener(updateCookies);
|
||||
// browser.tabs.onActivated.addListener(readCookies);
|
||||
// browser.runtime.onStartup.addListener(readCookies);
|
||||
|
||||
// browser.runtime.onMessage.addListener(handleMessage);
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es3",
|
||||
"target": "es2015",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"isolatedModules": false,
|
||||
"lib": [
|
||||
"ES2017",
|
||||
"ES6",
|
||||
"dom"
|
||||
],
|
||||
"strictNullChecks": true,
|
||||
|
Loading…
Reference in New Issue
Block a user