From cfc5fc699e7ff736d36fa0479b9d1a24caa07815 Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Mon, 9 Oct 2023 09:09:33 -0300 Subject: [PATCH] sketch api, remove desktop --- examples/api/src-tauri/Cargo.toml | 2 +- .../AppIcon.appiconset/Contents.json | 154 +++++++++--------- .../gen/apple/Assets.xcassets/Contents.json | 8 +- examples/api/src-tauri/src/lib.rs | 2 +- plugins/nfc/guest-js/index.ts | 48 +++++- plugins/nfc/ios/Sources/NfcPlugin.swift | 27 +-- plugins/nfc/src/api-iife.js | 2 +- plugins/nfc/src/desktop.rs | 26 --- plugins/nfc/src/lib.rs | 52 ++++-- plugins/nfc/src/mobile.rs | 29 ---- plugins/nfc/src/models.rs | 60 ++++++- 11 files changed, 235 insertions(+), 175 deletions(-) delete mode 100644 plugins/nfc/src/desktop.rs diff --git a/examples/api/src-tauri/Cargo.toml b/examples/api/src-tauri/Cargo.toml index d1cead09..e141bbf2 100644 --- a/examples/api/src-tauri/Cargo.toml +++ b/examples/api/src-tauri/Cargo.toml @@ -25,7 +25,6 @@ tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.0-alpha.2" } tauri-plugin-http = { path = "../../../plugins/http", features = [ "multipart" ], version = "2.0.0-alpha.3" } tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.0-alpha.3", features = [ "windows7-compat" ] } -tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "1.0.0" } tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.0-alpha.2" } tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.0-alpha.2" } tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.0-alpha.2" } @@ -49,6 +48,7 @@ tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.0.0-alp [target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies] tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.0.0-alpha.0" } +tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "1.0.0" } [target."cfg(target_os = \"windows\")".dependencies] window-shadows = "0.2" diff --git a/examples/api/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/api/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json index 90eea7ec..dd3b8bcc 100644 --- a/examples/api/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/examples/api/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,116 +1,116 @@ { - "images" : [ + "images": [ { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "AppIcon-20x20@2x.png", - "scale" : "2x" + "size": "20x20", + "idiom": "iphone", + "filename": "AppIcon-20x20@2x.png", + "scale": "2x" }, { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "AppIcon-20x20@3x.png", - "scale" : "3x" + "size": "20x20", + "idiom": "iphone", + "filename": "AppIcon-20x20@3x.png", + "scale": "3x" }, { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "AppIcon-29x29@2x-1.png", - "scale" : "2x" + "size": "29x29", + "idiom": "iphone", + "filename": "AppIcon-29x29@2x-1.png", + "scale": "2x" }, { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "AppIcon-29x29@3x.png", - "scale" : "3x" + "size": "29x29", + "idiom": "iphone", + "filename": "AppIcon-29x29@3x.png", + "scale": "3x" }, { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "AppIcon-40x40@2x.png", - "scale" : "2x" + "size": "40x40", + "idiom": "iphone", + "filename": "AppIcon-40x40@2x.png", + "scale": "2x" }, { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "AppIcon-40x40@3x.png", - "scale" : "3x" + "size": "40x40", + "idiom": "iphone", + "filename": "AppIcon-40x40@3x.png", + "scale": "3x" }, { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "AppIcon-60x60@2x.png", - "scale" : "2x" + "size": "60x60", + "idiom": "iphone", + "filename": "AppIcon-60x60@2x.png", + "scale": "2x" }, { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "AppIcon-60x60@3x.png", - "scale" : "3x" + "size": "60x60", + "idiom": "iphone", + "filename": "AppIcon-60x60@3x.png", + "scale": "3x" }, { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "AppIcon-20x20@1x.png", - "scale" : "1x" + "size": "20x20", + "idiom": "ipad", + "filename": "AppIcon-20x20@1x.png", + "scale": "1x" }, { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "AppIcon-20x20@2x-1.png", - "scale" : "2x" + "size": "20x20", + "idiom": "ipad", + "filename": "AppIcon-20x20@2x-1.png", + "scale": "2x" }, { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "AppIcon-29x29@1x.png", - "scale" : "1x" + "size": "29x29", + "idiom": "ipad", + "filename": "AppIcon-29x29@1x.png", + "scale": "1x" }, { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "AppIcon-29x29@2x.png", - "scale" : "2x" + "size": "29x29", + "idiom": "ipad", + "filename": "AppIcon-29x29@2x.png", + "scale": "2x" }, { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "AppIcon-40x40@1x.png", - "scale" : "1x" + "size": "40x40", + "idiom": "ipad", + "filename": "AppIcon-40x40@1x.png", + "scale": "1x" }, { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "AppIcon-40x40@2x-1.png", - "scale" : "2x" + "size": "40x40", + "idiom": "ipad", + "filename": "AppIcon-40x40@2x-1.png", + "scale": "2x" }, { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "AppIcon-76x76@1x.png", - "scale" : "1x" + "size": "76x76", + "idiom": "ipad", + "filename": "AppIcon-76x76@1x.png", + "scale": "1x" }, { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "AppIcon-76x76@2x.png", - "scale" : "2x" + "size": "76x76", + "idiom": "ipad", + "filename": "AppIcon-76x76@2x.png", + "scale": "2x" }, { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "AppIcon-83.5x83.5@2x.png", - "scale" : "2x" + "size": "83.5x83.5", + "idiom": "ipad", + "filename": "AppIcon-83.5x83.5@2x.png", + "scale": "2x" }, { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "AppIcon-512@2x.png", - "scale" : "1x" + "size": "1024x1024", + "idiom": "ios-marketing", + "filename": "AppIcon-512@2x.png", + "scale": "1x" } ], - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } -} \ No newline at end of file +} diff --git a/examples/api/src-tauri/gen/apple/Assets.xcassets/Contents.json b/examples/api/src-tauri/gen/apple/Assets.xcassets/Contents.json index da4a164c..97a8662e 100644 --- a/examples/api/src-tauri/gen/apple/Assets.xcassets/Contents.json +++ b/examples/api/src-tauri/gen/apple/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } -} \ No newline at end of file +} diff --git a/examples/api/src-tauri/src/lib.rs b/examples/api/src-tauri/src/lib.rs index a3507b54..1946b6c0 100644 --- a/examples/api/src-tauri/src/lib.rs +++ b/examples/api/src-tauri/src/lib.rs @@ -36,7 +36,6 @@ pub fn run() { .plugin(tauri_plugin_clipboard_manager::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_http::init()) - .plugin(tauri_plugin_nfc::init()) .plugin(tauri_plugin_notification::init()) .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_process::init()) @@ -55,6 +54,7 @@ pub fn run() { #[cfg(mobile)] { app.handle().plugin(tauri_plugin_barcode_scanner::init())?; + app.handle().plugin(tauri_plugin_nfc::init())?; } let mut window_builder = WindowBuilder::new(app, "main", WindowUrl::default()); diff --git a/plugins/nfc/guest-js/index.ts b/plugins/nfc/guest-js/index.ts index 38c5009c..da43aefa 100644 --- a/plugins/nfc/guest-js/index.ts +++ b/plugins/nfc/guest-js/index.ts @@ -2,6 +2,50 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -export async function scanNdef() {} +declare global { + interface Window { + __TAURI_INVOKE__: (cmd: string, args?: unknown) => Promise; + } +} -export async function scanTag() {} +export enum ScanKind { + Ndef, + Tag, +} + +export interface ScanOptions { + keepAlive?: boolean; +} + +export interface TagRecord { + tnf: number; + kind: number[]; + id: number[]; + payload: number[]; +} + +export interface Tag { + id: string; + kind: string; + records: TagRecord[]; +} + +export interface Scan { + id: string; + kind: string; + tag: Tag; +} + +export async function scan( + kind: ScanKind, + options?: ScanOptions, +): Promise { + return await window.__TAURI_INVOKE__("plugin:nfc|scan", { + kind: kind === ScanKind.Ndef ? "ndef" : "tag", + ...options, + }); +} + +export async function isAvailable(): Promise { + return await window.__TAURI_INVOKE__("plugin:nfc|isAvailable"); +} diff --git a/plugins/nfc/ios/Sources/NfcPlugin.swift b/plugins/nfc/ios/Sources/NfcPlugin.swift index 76bd77f1..caee8c23 100644 --- a/plugins/nfc/ios/Sources/NfcPlugin.swift +++ b/plugins/nfc/ios/Sources/NfcPlugin.swift @@ -45,7 +45,6 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega } func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) { - Logger.info("detected tags!") let tag = tags.first! session.connect( @@ -132,23 +131,23 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega switch tag { case .feliCa: - metadata["type"] = "FeliCa" + metadata["kind"] = "FeliCa" metadata["id"] = nil break case let .miFare(tag): - metadata["type"] = "MiFare" + metadata["kind"] = "MiFare" metadata["id"] = tag.identifier break case let .iso15693(tag): - metadata["type"] = "ISO15693" + metadata["kind"] = "ISO15693" metadata["id"] = tag.identifier break case let .iso7816(tag): - metadata["type"] = "ISO7816Compatible" + metadata["kind"] = "ISO7816Compatible" metadata["id"] = tag.identifier break default: - metadata["type"] = "Unknown" + metadata["kind"] = "Unknown" metadata["id"] = nil break } @@ -260,8 +259,8 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega var records: [JsonObject] = [] for record in message.records { var recordJson: JsonObject = [:] - recordJson["tnf"] = record.typeNameFormat - recordJson["type"] = record.type + recordJson["tnf"] = record.typeNameFormat.rawValue + recordJson["kind"] = record.type recordJson["id"] = record.identifier recordJson["payload"] = record.payload @@ -273,16 +272,22 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega return tag } + @objc func isAvailable(_ invoke: Invoke) { + invoke.resolve([ + "available": NFCNDEFReaderSession.readingAvailable + ]) + } + @objc public func scan(_ invoke: Invoke) { let kind: ScanKind switch invoke.getString("kind") { - case "tag": + case "tag": kind = .tag break - case "ndef": + case "ndef": kind = .ndef break - default: + default: invoke.reject("invalid `kind` argument, expected one of `tag`, `ndef`.") return } diff --git a/plugins/nfc/src/api-iife.js b/plugins/nfc/src/api-iife.js index 9480d5ff..a4faafe1 100644 --- a/plugins/nfc/src/api-iife.js +++ b/plugins/nfc/src/api-iife.js @@ -1 +1 @@ -if("__TAURI__"in window){var __TAURI_NFC__=function(_){"use strict";return _.scanNdef=async function(){},_.scanTag=async function(){},_}({});Object.defineProperty(window.__TAURI__,"nfc",{value:__TAURI_NFC__})} +if("__TAURI__"in window){var __TAURI_NFC__=function(n){"use strict";var _;return n.ScanKind=void 0,(_=n.ScanKind||(n.ScanKind={}))[_.Ndef=0]="Ndef",_[_.Tag=1]="Tag",n.isAvailable=async function(){return await window.__TAURI_INVOKE__("plugin:nfc|isAvailable")},n.scan=async function(_,i){return await window.__TAURI_INVOKE__("plugin:nfc|scan",{kind:_===n.ScanKind.Ndef?"ndef":"tag",...i})},n}({});Object.defineProperty(window.__TAURI__,"nfc",{value:__TAURI_NFC__})} diff --git a/plugins/nfc/src/desktop.rs b/plugins/nfc/src/desktop.rs deleted file mode 100644 index 24bc7990..00000000 --- a/plugins/nfc/src/desktop.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2019-2023 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use serde::de::DeserializeOwned; -use tauri::{plugin::PluginApi, AppHandle, Runtime}; - -use crate::models::*; - -pub fn init( - app: &AppHandle, - _api: PluginApi, -) -> crate::Result> { - Ok(Nfc(app.clone())) -} - -/// Access to the nfc APIs. -pub struct Nfc(AppHandle); - -impl Nfc { - pub fn ping(&self, payload: PingRequest) -> crate::Result { - Ok(PingResponse { - value: payload.value, - }) - } -} diff --git a/plugins/nfc/src/lib.rs b/plugins/nfc/src/lib.rs index cc2c79c4..b3d9da88 100644 --- a/plugins/nfc/src/lib.rs +++ b/plugins/nfc/src/lib.rs @@ -2,28 +2,50 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +#![cfg(mobile)] + +use serde::Deserialize; use tauri::{ - plugin::{Builder, TauriPlugin}, + plugin::{Builder, PluginHandle, TauriPlugin}, Manager, Runtime, }; pub use models::*; -#[cfg(desktop)] -mod desktop; -#[cfg(mobile)] -mod mobile; - mod commands; mod error; mod models; pub use error::{Error, Result}; -#[cfg(desktop)] -use desktop::Nfc; -#[cfg(mobile)] -use mobile::Nfc; +#[cfg(target_os = "android")] +const PLUGIN_IDENTIFIER: &str = "app.tauri.nfc"; + +#[cfg(target_os = "ios")] +tauri::ios_plugin_binding!(init_plugin_nfc); + +/// Access to the nfc APIs. +pub struct Nfc(PluginHandle); + +#[derive(Deserialize)] +struct IsAvailableResponse { + available: bool, +} + +impl Nfc { + pub fn is_available(&self) -> crate::Result { + self.0 + .run_mobile_plugin::("isAvailable", ()) + .map(|r| r.available) + .map_err(Into::into) + } + + pub fn scan(&self, payload: ScanRequest) -> crate::Result { + self.0 + .run_mobile_plugin("scan", payload) + .map_err(Into::into) + } +} /// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the nfc APIs. pub trait NfcExt { @@ -42,11 +64,11 @@ pub fn init() -> TauriPlugin { .js_init_script(include_str!("api-iife.js").to_string()) .invoke_handler(tauri::generate_handler![commands::execute]) .setup(|app, api| { - #[cfg(mobile)] - let nfc = mobile::init(app, api)?; - #[cfg(desktop)] - let nfc = desktop::init(app, api)?; - app.manage(nfc); + #[cfg(target_os = "android")] + let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "NfcPlugin")?; + #[cfg(target_os = "ios")] + let handle = api.register_ios_plugin(init_plugin_nfc)?; + app.manage(Nfc(handle)); Ok(()) }) .build() diff --git a/plugins/nfc/src/mobile.rs b/plugins/nfc/src/mobile.rs index 0c190b06..cf34d45e 100644 --- a/plugins/nfc/src/mobile.rs +++ b/plugins/nfc/src/mobile.rs @@ -9,32 +9,3 @@ use tauri::{ }; use crate::models::*; - -#[cfg(target_os = "android")] -const PLUGIN_IDENTIFIER: &str = "app.tauri.nfc"; - -#[cfg(target_os = "ios")] -tauri::ios_plugin_binding!(init_plugin_nfc); - -// initializes the Kotlin or Swift plugin classes -pub fn init( - _app: &AppHandle, - api: PluginApi, -) -> crate::Result> { - #[cfg(target_os = "android")] - let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "NfcPlugin")?; - #[cfg(target_os = "ios")] - let handle = api.register_ios_plugin(init_plugin_nfc)?; - Ok(Nfc(handle)) -} - -/// Access to the nfc APIs. -pub struct Nfc(PluginHandle); - -impl Nfc { - pub fn ping(&self, payload: PingRequest) -> crate::Result { - self.0 - .run_mobile_plugin("ping", payload) - .map_err(Into::into) - } -} diff --git a/plugins/nfc/src/models.rs b/plugins/nfc/src/models.rs index d50dcf91..f05a223c 100644 --- a/plugins/nfc/src/models.rs +++ b/plugins/nfc/src/models.rs @@ -2,16 +2,60 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; +use std::fmt::Display; -#[derive(Debug, Serialize)] +#[derive(Serialize)] #[serde(rename_all = "camelCase")] -pub struct PingRequest { - pub value: Option, +pub struct ScanRequest { + pub kind: ScanKind, + pub keep_alive: bool, } -#[derive(Debug, Clone, Default, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PingResponse { - pub value: Option, +#[derive(Deserialize)] +pub struct NfcTagRecord { + pub tnf: u8, + pub kind: Vec, + pub id: Vec, + pub payload: Vec, +} + +#[derive(Deserialize)] +pub struct NfcTag { + pub id: String, + pub kind: String, + pub records: Vec, +} + +#[derive(Deserialize)] +pub struct ScanResponse { + pub tag: NfcTag, +} + +#[derive(Debug)] +pub enum ScanKind { + Ndef, + Tag, +} + +impl Display for ScanKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::Ndef => "ndef", + Self::Tag => "tag", + } + ) + } +} + +impl Serialize for ScanKind { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_string()) + } }