fix(iap): open external app for payment (#2465)
This commit is contained in:
@@ -134,6 +134,14 @@
|
||||
"oauth:allow-cancel",
|
||||
"sign-in-with-apple:default",
|
||||
"opener:default",
|
||||
{
|
||||
"identifier": "opener:allow-open-url",
|
||||
"allow": [
|
||||
{
|
||||
"url": "alipays:*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"haptics:allow-vibrate",
|
||||
"haptics:allow-impact-feedback",
|
||||
"haptics:allow-notification-feedback",
|
||||
|
||||
+22
@@ -75,6 +75,11 @@ class SetScreenBrightnessRequestArgs {
|
||||
var brightness: Double? = null // 0.0 to 1.0
|
||||
}
|
||||
|
||||
@InvokeArg
|
||||
class OpenExternalUrlArgs {
|
||||
var url: String? = null
|
||||
}
|
||||
|
||||
@InvokeArg
|
||||
class FetchProductsRequestArgs {
|
||||
val productIds: List<String>? = null
|
||||
@@ -660,4 +665,21 @@ class NativeBridgePlugin(private val activity: Activity): Plugin(activity) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Command
|
||||
fun open_external_url(invoke: Invoke) {
|
||||
val args = invoke.parseArgs(OpenExternalUrlArgs::class.java)
|
||||
val url = args.url ?: ""
|
||||
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
activity.startActivity(intent)
|
||||
val ret = JSObject()
|
||||
ret.put("success", true)
|
||||
invoke.resolve(ret)
|
||||
} catch (e: Exception) {
|
||||
invoke.reject("Failed to open URL: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ const COMMANDS: &[&str] = &[
|
||||
"get_screen_brightness",
|
||||
"set_screen_brightness",
|
||||
"get_external_sdcard_path",
|
||||
"open_external_url",
|
||||
"request_manage_storage_permission",
|
||||
"check_permissions",
|
||||
"request_permissions",
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-open-external-url"
|
||||
description = "Enables the open_external_url command without any pre-configured scope."
|
||||
commands.allow = ["open_external_url"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-open-external-url"
|
||||
description = "Denies the open_external_url command without any pre-configured scope."
|
||||
commands.deny = ["open_external_url"]
|
||||
+27
@@ -23,6 +23,7 @@ Default permissions for the plugin
|
||||
- `allow-get-screen-brightness`
|
||||
- `allow-set-screen-brightness`
|
||||
- `allow-get-external-sdcard-path`
|
||||
- `allow-open-external-url`
|
||||
- `allow-request-manage-storage-permission`
|
||||
- `allow-check-permissions`
|
||||
- `allow-request-permissions`
|
||||
@@ -535,6 +536,32 @@ Denies the lock_screen_orientation command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`native-bridge:allow-open-external-url`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the open_external_url command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`native-bridge:deny-open-external-url`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the open_external_url command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`native-bridge:allow-request-permissions`
|
||||
|
||||
</td>
|
||||
|
||||
@@ -20,6 +20,7 @@ permissions = [
|
||||
"allow-get-screen-brightness",
|
||||
"allow-set-screen-brightness",
|
||||
"allow-get-external-sdcard-path",
|
||||
"allow-open-external-url",
|
||||
"allow-request-manage-storage-permission",
|
||||
"allow-check-permissions",
|
||||
"allow-request-permissions",
|
||||
|
||||
+14
-2
@@ -522,6 +522,18 @@
|
||||
"const": "deny-lock-screen-orientation",
|
||||
"markdownDescription": "Denies the lock_screen_orientation command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the open_external_url command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-open-external-url",
|
||||
"markdownDescription": "Enables the open_external_url command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the open_external_url command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-open-external-url",
|
||||
"markdownDescription": "Denies the open_external_url command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the request-permissions command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -607,10 +619,10 @@
|
||||
"markdownDescription": "Denies the use_background_audio command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-auth-with-safari`\n- `allow-auth-with-custom-tab`\n- `allow-copy-uri-to-path`\n- `allow-use-background-audio`\n- `allow-install-package`\n- `allow-set-system-ui-visibility`\n- `allow-get-status-bar-height`\n- `allow-get-sys-fonts-list`\n- `allow-intercept-keys`\n- `allow-lock-screen-orientation`\n- `allow-iap-initialize`\n- `allow-iap-fetch-products`\n- `allow-iap-purchase-product`\n- `allow-iap-restore-purchases`\n- `allow-get-system-color-scheme`\n- `allow-get-safe-area-insets`\n- `allow-get-screen-brightness`\n- `allow-set-screen-brightness`\n- `allow-get-external-sdcard-path`\n- `allow-request-manage-storage-permission`\n- `allow-check-permissions`\n- `allow-request-permissions`\n- `allow-checkPermissions`\n- `allow-requestPermissions`",
|
||||
"description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-auth-with-safari`\n- `allow-auth-with-custom-tab`\n- `allow-copy-uri-to-path`\n- `allow-use-background-audio`\n- `allow-install-package`\n- `allow-set-system-ui-visibility`\n- `allow-get-status-bar-height`\n- `allow-get-sys-fonts-list`\n- `allow-intercept-keys`\n- `allow-lock-screen-orientation`\n- `allow-iap-initialize`\n- `allow-iap-fetch-products`\n- `allow-iap-purchase-product`\n- `allow-iap-restore-purchases`\n- `allow-get-system-color-scheme`\n- `allow-get-safe-area-insets`\n- `allow-get-screen-brightness`\n- `allow-set-screen-brightness`\n- `allow-get-external-sdcard-path`\n- `allow-open-external-url`\n- `allow-request-manage-storage-permission`\n- `allow-check-permissions`\n- `allow-request-permissions`\n- `allow-checkPermissions`\n- `allow-requestPermissions`",
|
||||
"type": "string",
|
||||
"const": "default",
|
||||
"markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-auth-with-safari`\n- `allow-auth-with-custom-tab`\n- `allow-copy-uri-to-path`\n- `allow-use-background-audio`\n- `allow-install-package`\n- `allow-set-system-ui-visibility`\n- `allow-get-status-bar-height`\n- `allow-get-sys-fonts-list`\n- `allow-intercept-keys`\n- `allow-lock-screen-orientation`\n- `allow-iap-initialize`\n- `allow-iap-fetch-products`\n- `allow-iap-purchase-product`\n- `allow-iap-restore-purchases`\n- `allow-get-system-color-scheme`\n- `allow-get-safe-area-insets`\n- `allow-get-screen-brightness`\n- `allow-set-screen-brightness`\n- `allow-get-external-sdcard-path`\n- `allow-request-manage-storage-permission`\n- `allow-check-permissions`\n- `allow-request-permissions`\n- `allow-checkPermissions`\n- `allow-requestPermissions`"
|
||||
"markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-auth-with-safari`\n- `allow-auth-with-custom-tab`\n- `allow-copy-uri-to-path`\n- `allow-use-background-audio`\n- `allow-install-package`\n- `allow-set-system-ui-visibility`\n- `allow-get-status-bar-height`\n- `allow-get-sys-fonts-list`\n- `allow-intercept-keys`\n- `allow-lock-screen-orientation`\n- `allow-iap-initialize`\n- `allow-iap-fetch-products`\n- `allow-iap-purchase-product`\n- `allow-iap-restore-purchases`\n- `allow-get-system-color-scheme`\n- `allow-get-safe-area-insets`\n- `allow-get-screen-brightness`\n- `allow-set-screen-brightness`\n- `allow-get-external-sdcard-path`\n- `allow-open-external-url`\n- `allow-request-manage-storage-permission`\n- `allow-check-permissions`\n- `allow-request-permissions`\n- `allow-checkPermissions`\n- `allow-requestPermissions`"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -149,6 +149,14 @@ pub(crate) async fn get_external_sdcard_path<R: Runtime>(
|
||||
app.native_bridge().get_external_sdcard_path()
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub(crate) async fn open_external_url<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
payload: OpenExternalUrlRequest,
|
||||
) -> Result<OpenExternalUrlResponse> {
|
||||
app.native_bridge().open_external_url(payload)
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub(crate) async fn request_manage_storage_permission<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
|
||||
@@ -122,6 +122,13 @@ impl<R: Runtime> NativeBridge<R> {
|
||||
Err(crate::Error::UnsupportedPlatformError)
|
||||
}
|
||||
|
||||
pub fn open_external_url(
|
||||
&self,
|
||||
_payload: OpenExternalUrlRequest,
|
||||
) -> crate::Result<OpenExternalUrlResponse> {
|
||||
Err(crate::Error::UnsupportedPlatformError)
|
||||
}
|
||||
|
||||
pub fn request_manage_storage_permission(
|
||||
&self,
|
||||
) -> crate::Result<RequestManageStoragePermissionResponse> {
|
||||
|
||||
@@ -56,6 +56,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
commands::get_screen_brightness,
|
||||
commands::set_screen_brightness,
|
||||
commands::get_external_sdcard_path,
|
||||
commands::open_external_url,
|
||||
commands::request_manage_storage_permission,
|
||||
])
|
||||
.setup(|app, api| {
|
||||
|
||||
@@ -197,6 +197,17 @@ impl<R: Runtime> NativeBridge<R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Runtime> NativeBridge<R> {
|
||||
pub fn open_external_url(
|
||||
&self,
|
||||
payload: OpenExternalUrlRequest,
|
||||
) -> crate::Result<OpenExternalUrlResponse> {
|
||||
self.0
|
||||
.run_mobile_plugin("open_external_url", payload)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Runtime> NativeBridge<R> {
|
||||
pub fn request_manage_storage_permission(
|
||||
&self,
|
||||
|
||||
@@ -202,3 +202,16 @@ pub struct GetExternalSDCardPathResponse {
|
||||
pub struct RequestManageStoragePermissionResponse {
|
||||
pub manage_storage: String, // "granted", "denied", or "prompt"
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OpenExternalUrlRequest {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OpenExternalUrlResponse {
|
||||
pub success: bool,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
@@ -21,7 +21,11 @@ use tauri_plugin_fs::FsExt;
|
||||
mod macos;
|
||||
mod transfer_file;
|
||||
use tauri::{command, Emitter, WebviewUrl, WebviewWindowBuilder, Window};
|
||||
#[cfg(target_os = "android")]
|
||||
use tauri_plugin_native_bridge::{NativeBridgeExt, OpenExternalUrlRequest};
|
||||
use tauri_plugin_oauth::start;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
use transfer_file::{download_file, upload_file};
|
||||
|
||||
#[cfg(desktop)]
|
||||
@@ -257,9 +261,56 @@ pub fn run() {
|
||||
eprintln!("Failed to initialize tauri_plugin_log: {e}");
|
||||
};
|
||||
|
||||
let app_handle = app.handle().clone();
|
||||
let win_builder = WebviewWindowBuilder::new(app, "main", WebviewUrl::default())
|
||||
.background_throttling(BackgroundThrottlingPolicy::Disabled)
|
||||
.background_color(tauri::window::Color(50, 49, 48, 255));
|
||||
.background_color(tauri::window::Color(50, 49, 48, 255))
|
||||
.initialization_script(
|
||||
r#"
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
const isTauriLocal = window.location.protocol === 'tauri:' ||
|
||||
window.location.hostname === 'tauri.localhost';
|
||||
const needsSafeArea = !isTauriLocal;
|
||||
if (needsSafeArea && !document.getElementById('safe-area-style')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'safe-area-style';
|
||||
style.textContent = `
|
||||
body {
|
||||
padding-top: env(safe-area-inset-top) !important;
|
||||
padding-bottom: env(safe-area-inset-bottom) !important;
|
||||
padding-left: env(safe-area-inset-left) !important;
|
||||
padding-right: env(safe-area-inset-right) !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
});
|
||||
"#,
|
||||
)
|
||||
.on_navigation(move |url| {
|
||||
if url.scheme() == "alipays" || url.scheme() == "alipay" {
|
||||
let url_str = url.as_str().to_string();
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let handle = app_handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
match handle
|
||||
.native_bridge()
|
||||
.open_external_url(OpenExternalUrlRequest { url: url_str })
|
||||
{
|
||||
Ok(result) => println!("Result: {:?}", result),
|
||||
Err(e) => eprintln!("Error: {:?}", e),
|
||||
}
|
||||
});
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
let _ = app_handle.opener().open_url(url_str, None::<&str>);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
#[cfg(desktop)]
|
||||
let win_builder = win_builder.inner_size(800.0, 600.0).resizable(true);
|
||||
|
||||
@@ -328,7 +328,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({
|
||||
/>
|
||||
))}
|
||||
{viewMode === 'grid' && currentBookshelfItems.length > 0 && (
|
||||
<div className={clsx('mx-0 my-4 sm:mx-4')}>
|
||||
<div className={clsx('mx-0 my-2 sm:mx-4 sm:my-4')}>
|
||||
<button
|
||||
aria-label={_('Import Books')}
|
||||
className={clsx(
|
||||
|
||||
Reference in New Issue
Block a user