mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-08-20 04:27:29 +00:00
feat(android): LCEOnline auth
This commit is contained in:
parent
84697a67e2
commit
ca2fe8e258
|
|
@ -31,6 +31,11 @@
|
|||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".LceAuthActivity"
|
||||
android:exported="false"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
package com.emerald.legacy
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Message
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebSettings
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ProgressBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class LceAuthActivity : AppCompatActivity() {
|
||||
private lateinit var webView: WebView
|
||||
private lateinit var progressBar: ProgressBar
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val authUrl = intent.getStringExtra("authUrl")
|
||||
?: "https://mclegacyedition.xyz/internal/auth?appId=emerald_launcher"
|
||||
|
||||
progressBar = ProgressBar(this).apply {
|
||||
layoutParams = FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
}
|
||||
|
||||
webView = WebView(this).apply {
|
||||
settings.javaScriptEnabled = true
|
||||
settings.domStorageEnabled = true
|
||||
settings.databaseEnabled = true
|
||||
settings.loadWithOverviewMode = true
|
||||
settings.useWideViewPort = true
|
||||
settings.setSupportMultipleWindows(true)
|
||||
settings.javaScriptCanOpenWindowsAutomatically = true
|
||||
webViewClient = object : WebViewClient() {
|
||||
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean = handleAuthUrl(url)
|
||||
override fun shouldOverrideUrlLoading(
|
||||
view: WebView,
|
||||
request: WebResourceRequest
|
||||
): Boolean = handleAuthUrl(request.url.toString())
|
||||
|
||||
override fun onCreateWindow(
|
||||
view: WebView,
|
||||
isDialog: Boolean,
|
||||
isUserGesture: Boolean,
|
||||
resultMsg: Message
|
||||
): Boolean {
|
||||
val transport = resultMsg.obj as WebView.WebViewTransport
|
||||
transport.webView = webView
|
||||
resultMsg.sendToTarget()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
|
||||
handleAuthUrl(url)
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView, url: String) {
|
||||
progressBar.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val root = FrameLayout(this)
|
||||
root.addView(
|
||||
webView,
|
||||
FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
)
|
||||
val progressFrame = FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
progressFrame.gravity = Gravity.CENTER
|
||||
root.addView(progressBar, progressFrame)
|
||||
setContentView(root)
|
||||
webView.loadUrl(authUrl)
|
||||
}
|
||||
|
||||
private fun handleAuthUrl(url: String): Boolean {
|
||||
val uri = try {
|
||||
Uri.parse(url)
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
if (uri.scheme == "emerald" && uri.host == "lceonline") {
|
||||
val token = uri.getQueryParameter("token")
|
||||
if (token != null) {
|
||||
setResult(RESULT_OK, Intent().putExtra("lceAuthToken", token))
|
||||
} else {
|
||||
setResult(RESULT_CANCELED)
|
||||
}
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onBackPressed() {
|
||||
if (webView.canGoBack()) {
|
||||
webView.goBack()
|
||||
} else {
|
||||
setResult(Activity.RESULT_CANCELED)
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
(webView.parent as? ViewGroup)?.removeView(webView)
|
||||
webView.destroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.emerald.legacy
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResult
|
||||
import app.tauri.annotation.ActivityCallback
|
||||
import app.tauri.annotation.Command
|
||||
import app.tauri.annotation.TauriPlugin
|
||||
import app.tauri.plugin.Invoke
|
||||
import app.tauri.plugin.Plugin
|
||||
|
||||
@TauriPlugin
|
||||
class LceAuthPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
@Command
|
||||
fun startAuth(invoke: Invoke) {
|
||||
val intent = Intent(activity, LceAuthActivity::class.java)
|
||||
intent.putExtra(
|
||||
"authUrl",
|
||||
"https://mclegacyedition.xyz/internal/auth?appId=emerald_launcher"
|
||||
)
|
||||
startActivityForResult(invoke, intent, "authResult")
|
||||
}
|
||||
|
||||
@ActivityCallback
|
||||
fun authResult(invoke: Invoke, result: ActivityResult) {
|
||||
val token = if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.getStringExtra("lceAuthToken")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (!token.isNullOrEmpty()) {
|
||||
invoke.resolveObject(token)
|
||||
} else {
|
||||
invoke.reject("Authentication cancelled or failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ pub fn launch_bridge(instance_path: String, action: BridgeAction) -> Result<(),
|
|||
&intent,
|
||||
"addFlags",
|
||||
"(I)Landroid/content/Intent;",
|
||||
&[JValue::Int(0x10000000 as jint)],
|
||||
&[JValue::Int(0x10000000 as jint)], //neo: FLAG_ACTIVITY_NEW_TASK
|
||||
)?;
|
||||
|
||||
env.call_method(
|
||||
|
|
|
|||
35
src-tauri/src/lce_auth.rs
Normal file
35
src-tauri/src/lce_auth.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use tauri::plugin::{Builder, PluginHandle, TauriPlugin};
|
||||
use tauri::Wry;
|
||||
pub struct LceAuthState(pub PluginHandle<Wry>);
|
||||
pub fn init() -> TauriPlugin<Wry> {
|
||||
Builder::new("emerald-lce-auth")
|
||||
.setup(|app, api| {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
use tauri::Manager;
|
||||
let handle = api.register_android_plugin("com.emerald.legacy", "LceAuthPlugin")?;
|
||||
app.manage(LceAuthState(handle));
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn start_lce_auth(app: tauri::AppHandle) -> Result<String, String> {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
use tauri::Manager;
|
||||
let state = app.state::<LceAuthState>();
|
||||
state
|
||||
.0
|
||||
.run_mobile_plugin_async("startAuth", ())
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
let _ = app;
|
||||
Err("LCE Online auth is only supported on Android".into())
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ mod playtime;
|
|||
mod platform;
|
||||
mod networking;
|
||||
mod workshop_server;
|
||||
mod lce_auth;
|
||||
#[cfg(target_os = "android")]
|
||||
mod android_runtime;
|
||||
mod commands;
|
||||
|
|
@ -36,6 +37,7 @@ pub fn run() {
|
|||
let mut builder = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_deep_link::init())
|
||||
.plugin(webview_deep_link_interceptor())
|
||||
.plugin(lce_auth::init())
|
||||
.plugin(tauri_plugin_process::init())
|
||||
.plugin(tauri_plugin_gamepad::init())
|
||||
.plugin(tauri_plugin_opener::init());
|
||||
|
|
@ -136,6 +138,7 @@ pub fn run() {
|
|||
relay::stop_proxy,
|
||||
relay::stop_all_proxies,
|
||||
relay::join_game,
|
||||
lce_auth::start_lce_auth,
|
||||
plugins::get_plugins_dir,
|
||||
plugins::list_directory,
|
||||
plugins::create_plugin_dir,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
useGame,
|
||||
} from "../../context/LauncherContext";
|
||||
import ChooseInstanceModal from "../modals/ChooseInstanceModal";
|
||||
import { usePlatform } from "../../hooks/usePlatform";
|
||||
import { lceOnlineService, SocialEntry } from "../../services/LceOnlineService";
|
||||
import { TauriService } from "../../services/TauriService";
|
||||
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
|
|
@ -28,6 +29,7 @@ const LceOnlineView = memo(function LceOnlineView({
|
|||
const { setActiveView, setIsUiHidden } = useUI();
|
||||
const { animationsEnabled } = useConfig();
|
||||
const { playPressSound, playBackSound } = useAudio();
|
||||
const { isAndroid } = usePlatform();
|
||||
const game = useGame();
|
||||
const [isSignedIn, setIsSignedIn] = useState(lceOnlineService.signedIn);
|
||||
const opened = useRef(false);
|
||||
|
|
@ -80,25 +82,41 @@ const LceOnlineView = memo(function LceOnlineView({
|
|||
|
||||
if (!opened.current) {
|
||||
opened.current = true;
|
||||
new WebviewWindow('LCEOnline', {
|
||||
url: "https://mclegacyedition.xyz/internal/auth?appId=emerald_launcher",
|
||||
width: 400,
|
||||
height: 570,
|
||||
resizable: false,
|
||||
title: 'Emerald Legacy Launcher - LCEOnline',
|
||||
});
|
||||
if (isAndroid) {
|
||||
TauriService.startLceOnlineAuth()
|
||||
.then((token) => {
|
||||
lceOnlineService
|
||||
.loginWithTokenAndFetchAccount(token)
|
||||
.catch((e) => console.error(e));
|
||||
setIsSignedIn(true);
|
||||
})
|
||||
.catch((e) => console.error("LCE Online auth failed", e));
|
||||
} else {
|
||||
new WebviewWindow('LCEOnline', {
|
||||
url: "https://mclegacyedition.xyz/internal/auth?appId=emerald_launcher",
|
||||
width: 400,
|
||||
height: 570,
|
||||
resizable: false,
|
||||
title: 'Emerald Legacy Launcher - LCEOnline',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const unlisten = listen<string[]>('deep-link', async (event) => {
|
||||
const authUrl = event.payload.find(u => u.startsWith('emerald://'));
|
||||
if (!authUrl) return;
|
||||
const token = new URL(authUrl).searchParams.get('token');
|
||||
if (token) setIsSignedIn(true);
|
||||
if (token) {
|
||||
lceOnlineService
|
||||
.loginWithTokenAndFetchAccount(token)
|
||||
.catch((e) => console.error(e));
|
||||
setIsSignedIn(true);
|
||||
}
|
||||
(await WebviewWindow.getByLabel('LCEOnline'))?.close();
|
||||
});
|
||||
|
||||
return () => { unlisten.then(f => f()); };
|
||||
}, [isSignedIn]);
|
||||
}, [isSignedIn, isAndroid]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!addFriendTarget) return;
|
||||
|
|
|
|||
|
|
@ -238,6 +238,10 @@ export class TauriService {
|
|||
return invoke("plugin:opener|open_url", { url });
|
||||
}
|
||||
|
||||
static async startLceOnlineAuth(): Promise<string> {
|
||||
return invoke("start_lce_auth");
|
||||
}
|
||||
|
||||
static async restartLauncher(): Promise<void> {
|
||||
return invoke("restart_launcher");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue