add write fn

pull/830/head
Lucas Nogueira 2 years ago
parent 6794455208
commit 175faeb664
No known key found for this signature in database
GPG Key ID: 3AFF5CAD641DD470

@ -14,7 +14,7 @@ export enum ScanKind {
} }
export interface ScanOptions { export interface ScanOptions {
keepAlive?: boolean; keepSessionAlive?: boolean;
} }
export enum NFCTypeNameFormat { export enum NFCTypeNameFormat {
@ -46,6 +46,13 @@ export interface Scan {
tag: Tag; tag: Tag;
} }
export interface NFCRecord {
format: NFCTypeNameFormat;
kind: number[];
id: number[];
payload: number[];
}
export async function scan( export async function scan(
kind: ScanKind, kind: ScanKind,
options?: ScanOptions, options?: ScanOptions,
@ -56,6 +63,12 @@ export async function scan(
}); });
} }
export async function write(records: NFCRecord[]): Promise<void> {
return await window.__TAURI_INVOKE__("plugin:nfc|write", {
records,
});
}
export async function isAvailable(): Promise<boolean> { export async function isAvailable(): Promise<boolean> {
return await window.__TAURI_INVOKE__("plugin:nfc|isAvailable"); return await window.__TAURI_INVOKE__("plugin:nfc|isAvailable");
} }

@ -19,7 +19,7 @@ enum TagProcessMode {
class Session { class Session {
let nfcSession: NFCReaderSession? let nfcSession: NFCReaderSession?
let invoke: Invoke let invoke: Invoke
let keepAlive: Bool var keepAlive: Bool
let tagProcessMode: TagProcessMode let tagProcessMode: TagProcessMode
var tagStatus: NFCNDEFStatus? var tagStatus: NFCNDEFStatus?
var tag: NFCNDEFTag? var tag: NFCNDEFTag?
@ -51,9 +51,8 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
to: tag, to: tag,
completionHandler: { [self] (error) in completionHandler: { [self] (error) in
if let error = error { if let error = error {
if self.session?.keepAlive != true { self.closeSession(session, error: "cannot connect to tag: \(error)")
self.closeSession(session, error: "cannot connect to tag: \(error)")
}
} else { } else {
let ndefTag: NFCNDEFTag let ndefTag: NFCNDEFTag
switch tag { switch tag {
@ -101,9 +100,8 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
to: tag, to: tag,
completionHandler: { [self] (error) in completionHandler: { [self] (error) in
if let error = error { if let error = error {
if self.session?.keepAlive != true { self.closeSession(session, error: "cannot connect to tag: \(error)")
self.closeSession(session, error: "cannot connect to tag: \(error)")
}
} else { } else {
self.processTag( self.processTag(
session: session, tag: tag, metadata: [:], session: session, tag: tag, metadata: [:],
@ -171,9 +169,7 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
tag.queryNDEFStatus(completionHandler: { tag.queryNDEFStatus(completionHandler: {
[self] (status, capacity, error) in [self] (status, capacity, error) in
if let error = error { if let error = error {
if self.session?.keepAlive != true { self.closeSession(session, error: "cannot connect to tag: \(error)")
self.closeSession(session, error: "cannot connect to tag: \(error)")
}
} else { } else {
switch mode { switch mode {
case .write: case .write:
@ -206,13 +202,14 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
currentSession.writeMessage!, currentSession.writeMessage!,
completionHandler: { (error) in completionHandler: { (error) in
if let error = error { if let error = error {
if currentSession.keepAlive != true { self.closeSession(session, error: "cannot write to tag: \(error)")
self.closeSession(session, error: "cannot write to tag: \(error)")
}
} else { } else {
session.alertMessage = "Data wrote to NFC tag" session.alertMessage = "Data wrote to NFC tag"
currentSession.invoke.resolve() currentSession.invoke.resolve()
self.closeSession(session)
if currentSession.keepAlive != true {
self.closeSession(session)
}
} }
}) })
} }
@ -223,8 +220,26 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
} }
private func readNDEFTag<T: NFCNDEFTag>( private func readNDEFTag<T: NFCNDEFTag>(
session: NFCReaderSession, status: NFCNDEFStatus, tag: T, metadata: JsonObject session: NFCReaderSession, status: NFCNDEFStatus, tag: T, metadata m: JsonObject
) { ) {
var metadata: JsonObject = [:]
metadata.merge(m) { (_, new) in new }
switch status {
case .notSupported:
self.resolveInvoke(message: nil, metadata: metadata)
self.closeSession(session)
return
case .readOnly:
metadata["readOnly"] = true
break
case .readWrite:
metadata["readOnly"] = false
break
default:
break
}
tag.readNDEF(completionHandler: { tag.readNDEF(completionHandler: {
[self] (message, error) in [self] (message, error) in
if let error = error { if let error = error {
@ -237,7 +252,10 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
session.alertMessage = "Successfully read tag" session.alertMessage = "Successfully read tag"
self.resolveInvoke(message: message, metadata: metadata) self.resolveInvoke(message: message, metadata: metadata)
self.closeSession(session)
if self.session?.keepAlive != true {
self.closeSession(session)
}
}) })
} }
@ -280,12 +298,62 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
return arr return arr
} }
private func dataFromByteArray(_ array: [UInt8]) -> Data {
var data = Data(capacity: array.count)
data.append(contentsOf: array)
return data
}
@objc func isAvailable(_ invoke: Invoke) { @objc func isAvailable(_ invoke: Invoke) {
invoke.resolve([ invoke.resolve([
"available": NFCNDEFReaderSession.readingAvailable "available": NFCNDEFReaderSession.readingAvailable
]) ])
} }
@objc public func write(_ invoke: Invoke) {
guard let records = invoke.getArray("records", JSObject.self) else {
invoke.reject("`records` array is required")
return
}
var ndefPayloads = [NFCNDEFPayload]()
for record in records {
let format = record["format"] as? NSNumber ?? 0
let type = record["kind"] as? [UInt8] ?? []
let identifier = record["id"] as? [UInt8] ?? []
let payload = record["payload"] as? [UInt8] ?? []
ndefPayloads.append(
NFCNDEFPayload(
format: NFCTypeNameFormat(rawValue: UInt8(truncating: format)) ?? .unknown,
type: dataFromByteArray(type),
identifier: dataFromByteArray(identifier),
payload: dataFromByteArray(payload)
)
)
}
if let session = self.session {
session.writeMessage = NFCNDEFMessage(records: ndefPayloads)
if let nfcSession = session.nfcSession, let tagStatus = session.tagStatus,
let tag = session.tag
{
session.keepAlive = false
self.writeNDEFTag(session: nfcSession, status: tagStatus, tag: tag)
} else {
invoke.reject(
"connected tag not found, please wait for it to be available and then call write()")
}
} else {
self.startScanSession(
invoke: invoke, kind: .ndef, keepAlive: false, invalidateAfterFirstRead: false,
tagProcessMode: .write)
}
}
@objc public func scan(_ invoke: Invoke) { @objc public func scan(_ invoke: Invoke) {
let kind: ScanKind let kind: ScanKind
switch invoke.getString("kind") { switch invoke.getString("kind") {
@ -299,11 +367,15 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
invoke.reject("invalid `kind` argument, expected one of `tag`, `ndef`.") invoke.reject("invalid `kind` argument, expected one of `tag`, `ndef`.")
return return
} }
self.startScanSession(invoke: invoke, kind: kind) self.startScanSession(
invoke: invoke, kind: kind, keepAlive: invoke.getBool("keepSessionAlive", false),
invalidateAfterFirstRead: true, tagProcessMode: .read)
} }
private func startScanSession(invoke: Invoke, kind: ScanKind) { private func startScanSession(
let keepAlive = invoke.getBool("keepAlive", false) invoke: Invoke, kind: ScanKind, keepAlive: Bool, invalidateAfterFirstRead: Bool,
tagProcessMode: TagProcessMode
) {
let nfcSession: NFCReaderSession? let nfcSession: NFCReaderSession?
switch kind { switch kind {
@ -318,7 +390,7 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
nfcSession = NFCNDEFReaderSession( nfcSession = NFCNDEFReaderSession(
delegate: self, delegate: self,
queue: DispatchQueue.main, queue: DispatchQueue.main,
invalidateAfterFirstRead: true invalidateAfterFirstRead: invalidateAfterFirstRead
) )
break break
} }
@ -327,7 +399,7 @@ class NfcPlugin: Plugin, NFCTagReaderSessionDelegate, NFCNDEFReaderSessionDelega
nfcSession?.begin() nfcSession?.begin()
self.session = Session( self.session = Session(
nfcSession: nfcSession, invoke: invoke, keepAlive: keepAlive, tagProcessMode: .read) nfcSession: nfcSession, invoke: invoke, keepAlive: keepAlive, tagProcessMode: tagProcessMode)
} }
} }

@ -1 +1 @@
if("__TAURI__"in window){var __TAURI_NFC__=function(n){"use strict";var a,e;return n.ScanKind=void 0,(a=n.ScanKind||(n.ScanKind={}))[a.Ndef=0]="Ndef",a[a.Tag=1]="Tag",n.NFCTypeNameFormat=void 0,(e=n.NFCTypeNameFormat||(n.NFCTypeNameFormat={}))[e.Empty=0]="Empty",e[e.NfcWellKnown=1]="NfcWellKnown",e[e.Media=2]="Media",e[e.AbsoluteURI=3]="AbsoluteURI",e[e.NfcExternal=4]="NfcExternal",e[e.Unknown=5]="Unknown",e[e.Unchanged=6]="Unchanged",n.isAvailable=async function(){return await window.__TAURI_INVOKE__("plugin:nfc|isAvailable")},n.scan=async function(a,e){return await window.__TAURI_INVOKE__("plugin:nfc|scan",{kind:a===n.ScanKind.Ndef?"ndef":"tag",...e})},n}({});Object.defineProperty(window.__TAURI__,"nfc",{value:__TAURI_NFC__})} if("__TAURI__"in window){var __TAURI_NFC__=function(n){"use strict";var a,e;return n.ScanKind=void 0,(a=n.ScanKind||(n.ScanKind={}))[a.Ndef=0]="Ndef",a[a.Tag=1]="Tag",n.NFCTypeNameFormat=void 0,(e=n.NFCTypeNameFormat||(n.NFCTypeNameFormat={}))[e.Empty=0]="Empty",e[e.NfcWellKnown=1]="NfcWellKnown",e[e.Media=2]="Media",e[e.AbsoluteURI=3]="AbsoluteURI",e[e.NfcExternal=4]="NfcExternal",e[e.Unknown=5]="Unknown",e[e.Unchanged=6]="Unchanged",n.isAvailable=async function(){return await window.__TAURI_INVOKE__("plugin:nfc|isAvailable")},n.scan=async function(a,e){return await window.__TAURI_INVOKE__("plugin:nfc|scan",{kind:a===n.ScanKind.Ndef?"ndef":"tag",...e})},n.write=async function(n){return await window.__TAURI_INVOKE__("plugin:nfc|write",{records:n})},n}({});Object.defineProperty(window.__TAURI__,"nfc",{value:__TAURI_NFC__})}

@ -4,7 +4,7 @@
#![cfg(mobile)] #![cfg(mobile)]
use serde::Deserialize; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
plugin::{Builder, PluginHandle, TauriPlugin}, plugin::{Builder, PluginHandle, TauriPlugin},
Manager, Runtime, Manager, Runtime,
@ -32,6 +32,11 @@ struct IsAvailableResponse {
available: bool, available: bool,
} }
#[derive(Serialize)]
struct WriteRequest {
records: Vec<NfcRecord>,
}
impl<R: Runtime> Nfc<R> { impl<R: Runtime> Nfc<R> {
pub fn is_available(&self) -> crate::Result<bool> { pub fn is_available(&self) -> crate::Result<bool> {
self.0 self.0
@ -45,6 +50,12 @@ impl<R: Runtime> Nfc<R> {
.run_mobile_plugin("scan", payload) .run_mobile_plugin("scan", payload)
.map_err(Into::into) .map_err(Into::into)
} }
pub fn write(&self, records: Vec<NfcRecord>) -> crate::Result<()> {
self.0
.run_mobile_plugin("write", WriteRequest { records })
.map_err(Into::into)
}
} }
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the nfc APIs. /// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the nfc APIs.

@ -9,10 +9,19 @@ use std::fmt::Display;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ScanRequest { pub struct ScanRequest {
pub kind: ScanKind, pub kind: ScanKind,
pub keep_alive: bool, pub keep_session_alive: bool,
} }
#[derive(serde_repr::Deserialize_repr)] #[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NfcRecord {
pub format: NFCTypeNameFormat,
pub kind: Vec<u8>,
pub id: Vec<u8>,
pub payload: Vec<u8>,
}
#[derive(serde_repr::Deserialize_repr, serde_repr::Serialize_repr)]
#[repr(u8)] #[repr(u8)]
pub enum NFCTypeNameFormat { pub enum NFCTypeNameFormat {
Empty = 0, Empty = 0,

Loading…
Cancel
Save