diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..50d8e32
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+/.vs
+.DS_Store
+.Thumbs.db
+*.sublime*
+.idea/
+debug.log
+package-lock.json
+.vscode/settings.json
+yarn.lock
+
+/.tauri
+/target
+Cargo.lock
+node_modules/
+
+dist-js
+dist
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..6f02d8a
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "tauri-plugin-bluclas"
+version = "0.1.0"
+authors = [ "You" ]
+description = ""
+edition = "2021"
+rust-version = "1.77.2"
+exclude = ["/examples", "/dist-js", "/guest-js", "/node_modules"]
+links = "tauri-plugin-bluclas"
+
+[dependencies]
+tauri = { version = "2.10.3" }
+serde = "1.0"
+thiserror = "2"
+
+[build-dependencies]
+tauri-plugin = { version = "2.5.4", features = ["build"] }
diff --git a/README.md b/README.md
index 0d4955f..14dbf06 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1 @@
-# bluclas
-
+# Tauri Plugin bluclas
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..e0ff2cc
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,8 @@
+const COMMANDS: &[&str] = &["ping"];
+
+fn main() {
+ tauri_plugin::Builder::new(COMMANDS)
+ .android_path("android")
+ .ios_path("ios")
+ .build();
+}
diff --git a/examples/tauri-app/.gitignore b/examples/tauri-app/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/examples/tauri-app/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/tauri-app/.vscode/extensions.json b/examples/tauri-app/.vscode/extensions.json
new file mode 100644
index 0000000..61343e9
--- /dev/null
+++ b/examples/tauri-app/.vscode/extensions.json
@@ -0,0 +1,7 @@
+{
+ "recommendations": [
+ "svelte.svelte-vscode",
+ "tauri-apps.tauri-vscode",
+ "rust-lang.rust-analyzer"
+ ]
+}
diff --git a/examples/tauri-app/README.md b/examples/tauri-app/README.md
new file mode 100644
index 0000000..72726a1
--- /dev/null
+++ b/examples/tauri-app/README.md
@@ -0,0 +1,8 @@
+# Svelte + Vite
+
+This template should help get you started developing with Tauri and Svelte in Vite.
+
+## Recommended IDE Setup
+
+[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
+
diff --git a/examples/tauri-app/index.html b/examples/tauri-app/index.html
new file mode 100644
index 0000000..fad1c5d
--- /dev/null
+++ b/examples/tauri-app/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ Tauri + Svelte
+
+
+
+
+
+
+
diff --git a/examples/tauri-app/jsconfig.json b/examples/tauri-app/jsconfig.json
new file mode 100644
index 0000000..0882056
--- /dev/null
+++ b/examples/tauri-app/jsconfig.json
@@ -0,0 +1,34 @@
+{
+ "compilerOptions": {
+ "moduleResolution": "bundler",
+ "target": "ESNext",
+ "module": "ESNext",
+ /**
+ * svelte-preprocess cannot figure out whether you have
+ * a value or a type, so tell TypeScript to enforce using
+ * `import type` instead of `import` for Types.
+ */
+ "verbatimModuleSyntax": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true,
+ /**
+ * To have warnings / errors of the Svelte compiler at the
+ * correct position, enable source maps by default.
+ */
+ "sourceMap": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "baseUrl": ".",
+ /**
+ * Typecheck JS in `.svelte` and `.js` files by default.
+ * Disable this if you'd like to use dynamic types.
+ */
+ "checkJs": true
+ },
+ /**
+ * Use global.d.ts instead of compilerOptions.types
+ * to avoid limiting type declarations.
+ */
+ "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
+}
diff --git a/examples/tauri-app/package.json b/examples/tauri-app/package.json
new file mode 100644
index 0000000..7c1a5b4
--- /dev/null
+++ b/examples/tauri-app/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "tauri-app",
+ "private": true,
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "tauri": "tauri"
+ },
+ "dependencies": {
+ "@tauri-apps/api": "^2.0.0",
+ "tauri-plugin-bluclas-api": "file:../../"
+ },
+ "devDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^6.0.0",
+ "svelte": "^5.0.0",
+ "vite": "^7.0.0",
+ "@tauri-apps/cli": "^2.0.0"
+ }
+}
diff --git a/examples/tauri-app/public/svelte.svg b/examples/tauri-app/public/svelte.svg
new file mode 100644
index 0000000..c5e0848
--- /dev/null
+++ b/examples/tauri-app/public/svelte.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/tauri-app/public/tauri.svg b/examples/tauri-app/public/tauri.svg
new file mode 100644
index 0000000..31b62c9
--- /dev/null
+++ b/examples/tauri-app/public/tauri.svg
@@ -0,0 +1,6 @@
+
diff --git a/examples/tauri-app/public/vite.svg b/examples/tauri-app/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/examples/tauri-app/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/tauri-app/src-tauri/.gitignore b/examples/tauri-app/src-tauri/.gitignore
new file mode 100644
index 0000000..f4dfb82
--- /dev/null
+++ b/examples/tauri-app/src-tauri/.gitignore
@@ -0,0 +1,4 @@
+# Generated by Cargo
+# will have compiled files and executables
+/target/
+
diff --git a/examples/tauri-app/src-tauri/Cargo.toml b/examples/tauri-app/src-tauri/Cargo.toml
new file mode 100644
index 0000000..f358d25
--- /dev/null
+++ b/examples/tauri-app/src-tauri/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "tauri-app"
+version = "0.1.0"
+description = "A Tauri App"
+authors = ["you"]
+license = ""
+repository = ""
+edition = "2021"
+rust-version = "1.77.2"
+
+[lib]
+name = "tauri_app_lib"
+crate-type = ["staticlib", "cdylib", "rlib"]
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[build-dependencies]
+tauri-build = { version = "2.5.6", default-features = false }
+
+[dependencies]
+tauri = { version = "2.10.3" }
+tauri-plugin-bluclas = { path = "../../../" }
+
diff --git a/examples/tauri-app/src-tauri/build.rs b/examples/tauri-app/src-tauri/build.rs
new file mode 100644
index 0000000..795b9b7
--- /dev/null
+++ b/examples/tauri-app/src-tauri/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+ tauri_build::build()
+}
diff --git a/examples/tauri-app/src-tauri/capabilities/default.json b/examples/tauri-app/src-tauri/capabilities/default.json
new file mode 100644
index 0000000..85caf85
--- /dev/null
+++ b/examples/tauri-app/src-tauri/capabilities/default.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "../gen/schemas/desktop-schema.json",
+ "identifier": "default",
+ "description": "enables the default permissions",
+ "windows": [
+ "main"
+ ],
+ "permissions": [
+ "core:default",
+ "bluclas:default"
+ ]
+}
diff --git a/examples/tauri-app/src-tauri/icons/128x128.png b/examples/tauri-app/src-tauri/icons/128x128.png
new file mode 100644
index 0000000..77e7d23
Binary files /dev/null and b/examples/tauri-app/src-tauri/icons/128x128.png differ
diff --git a/examples/tauri-app/src-tauri/icons/128x128@2x.png b/examples/tauri-app/src-tauri/icons/128x128@2x.png
new file mode 100644
index 0000000..0f7976f
Binary files /dev/null and b/examples/tauri-app/src-tauri/icons/128x128@2x.png differ
diff --git a/examples/tauri-app/src-tauri/icons/32x32.png b/examples/tauri-app/src-tauri/icons/32x32.png
new file mode 100644
index 0000000..98fda06
Binary files /dev/null and b/examples/tauri-app/src-tauri/icons/32x32.png differ
diff --git a/examples/tauri-app/src-tauri/icons/icon.icns b/examples/tauri-app/src-tauri/icons/icon.icns
new file mode 100644
index 0000000..29d6685
Binary files /dev/null and b/examples/tauri-app/src-tauri/icons/icon.icns differ
diff --git a/examples/tauri-app/src-tauri/icons/icon.ico b/examples/tauri-app/src-tauri/icons/icon.ico
new file mode 100644
index 0000000..06c23c8
Binary files /dev/null and b/examples/tauri-app/src-tauri/icons/icon.ico differ
diff --git a/examples/tauri-app/src-tauri/icons/icon.png b/examples/tauri-app/src-tauri/icons/icon.png
new file mode 100644
index 0000000..d1756ce
Binary files /dev/null and b/examples/tauri-app/src-tauri/icons/icon.png differ
diff --git a/examples/tauri-app/src-tauri/src/lib.rs b/examples/tauri-app/src-tauri/src/lib.rs
new file mode 100644
index 0000000..405d260
--- /dev/null
+++ b/examples/tauri-app/src-tauri/src/lib.rs
@@ -0,0 +1,14 @@
+// Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands
+#[tauri::command]
+fn greet(name: &str) -> String {
+ format!("Hello, {}! You've been greeted from Rust!", name)
+}
+
+#[cfg_attr(mobile, tauri::mobile_entry_point)]
+pub fn run() {
+ tauri::Builder::default()
+ .invoke_handler(tauri::generate_handler![greet])
+ .plugin(tauri_plugin_bluclas::init())
+ .run(tauri::generate_context!())
+ .expect("error while running tauri application");
+}
diff --git a/examples/tauri-app/src-tauri/src/main.rs b/examples/tauri-app/src-tauri/src/main.rs
new file mode 100644
index 0000000..455963e
--- /dev/null
+++ b/examples/tauri-app/src-tauri/src/main.rs
@@ -0,0 +1,6 @@
+// Prevents additional console window on Windows in release, DO NOT REMOVE!!
+#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+
+fn main() {
+ tauri_app_lib::run();
+}
diff --git a/examples/tauri-app/src-tauri/tauri.conf.json b/examples/tauri-app/src-tauri/tauri.conf.json
new file mode 100644
index 0000000..72ebf40
--- /dev/null
+++ b/examples/tauri-app/src-tauri/tauri.conf.json
@@ -0,0 +1,37 @@
+{
+ "productName": "tauri-app",
+ "version": "0.1.0",
+ "identifier": "com.tauri.dev",
+ "build": {
+ "beforeDevCommand": "pnpm dev",
+ "beforeBuildCommand": "pnpm build",
+ "devUrl": "http://localhost:1420",
+ "frontendDist": "../dist"
+ },
+ "app": {
+ "withGlobalTauri": false,
+ "security": {
+ "csp": null
+ },
+ "windows": [
+ {
+ "fullscreen": false,
+ "height": 600,
+ "resizable": true,
+ "title": "tauri-app",
+ "width": 800
+ }
+ ]
+ },
+ "bundle": {
+ "active": true,
+ "targets": "all",
+ "icon": [
+ "icons/32x32.png",
+ "icons/128x128.png",
+ "icons/128x128@2x.png",
+ "icons/icon.icns",
+ "icons/icon.ico"
+ ]
+ }
+}
diff --git a/examples/tauri-app/src/App.svelte b/examples/tauri-app/src/App.svelte
new file mode 100644
index 0000000..6e2a1d2
--- /dev/null
+++ b/examples/tauri-app/src/App.svelte
@@ -0,0 +1,54 @@
+
+
+
+ Welcome to Tauri!
+
+
+
+
+ Click on the Tauri, Vite, and Svelte logos to learn more.
+
+
+
+
+
+
+
+
+
{@html response}
+
+
+
+
+
diff --git a/examples/tauri-app/src/lib/Greet.svelte b/examples/tauri-app/src/lib/Greet.svelte
new file mode 100644
index 0000000..1da5e30
--- /dev/null
+++ b/examples/tauri-app/src/lib/Greet.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
{greetMsg}
+
+
diff --git a/examples/tauri-app/src/main.js b/examples/tauri-app/src/main.js
new file mode 100644
index 0000000..d3398c8
--- /dev/null
+++ b/examples/tauri-app/src/main.js
@@ -0,0 +1,9 @@
+import "./style.css";
+import App from "./App.svelte";
+import { mount } from 'svelte';
+
+const app = mount(App, {
+ target: document.getElementById("app"),
+});
+
+export default app;
diff --git a/examples/tauri-app/src/style.css b/examples/tauri-app/src/style.css
new file mode 100644
index 0000000..c0f9e3b
--- /dev/null
+++ b/examples/tauri-app/src/style.css
@@ -0,0 +1,102 @@
+:root {
+ font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ line-height: 24px;
+ font-weight: 400;
+
+ color: #0f0f0f;
+ background-color: #f6f6f6;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+.container {
+ margin: 0;
+ padding-top: 10vh;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: 0.75s;
+}
+
+.logo.tauri:hover {
+ filter: drop-shadow(0 0 2em #24c8db);
+}
+
+.row {
+ display: flex;
+ justify-content: center;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+
+a:hover {
+ color: #535bf2;
+}
+
+h1 {
+ text-align: center;
+}
+
+input,
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ color: #0f0f0f;
+ background-color: #ffffff;
+ transition: border-color 0.25s;
+ box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
+}
+
+button {
+ cursor: pointer;
+}
+
+button:hover {
+ border-color: #396cd8;
+}
+
+input,
+button {
+ outline: none;
+}
+
+#greet-input {
+ margin-right: 5px;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ color: #f6f6f6;
+ background-color: #2f2f2f;
+ }
+
+ a:hover {
+ color: #24c8db;
+ }
+
+ input,
+ button {
+ color: #ffffff;
+ background-color: #0f0f0f98;
+ }
+}
diff --git a/examples/tauri-app/src/vite-env.d.ts b/examples/tauri-app/src/vite-env.d.ts
new file mode 100644
index 0000000..4078e74
--- /dev/null
+++ b/examples/tauri-app/src/vite-env.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/examples/tauri-app/vite.config.js b/examples/tauri-app/vite.config.js
new file mode 100644
index 0000000..82e1f23
--- /dev/null
+++ b/examples/tauri-app/vite.config.js
@@ -0,0 +1,24 @@
+import { defineConfig } from "vite";
+import { svelte } from "@sveltejs/vite-plugin-svelte";
+
+const host = process.env.TAURI_DEV_HOST;
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [svelte()],
+
+ // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
+ // prevent Vite from obscuring rust errors
+ clearScreen: false,
+ // tauri expects a fixed port, fail if that port is not available
+ server: {
+ host: host || false,
+ port: 1420,
+ strictPort: true,
+ hmr: host ? {
+ protocol: 'ws',
+ host,
+ port: 1421
+ } : undefined,
+ },
+})
diff --git a/guest-js/index.ts b/guest-js/index.ts
new file mode 100644
index 0000000..fca440d
--- /dev/null
+++ b/guest-js/index.ts
@@ -0,0 +1,9 @@
+import { invoke } from '@tauri-apps/api/core'
+
+export async function ping(value: string): Promise {
+ return await invoke<{value?: string}>('plugin:bluclas|ping', {
+ payload: {
+ value,
+ },
+ }).then((r) => (r.value ? r.value : null));
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..fc79e8d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "tauri-plugin-bluclas-api",
+ "version": "0.1.0",
+ "author": "You",
+ "description": "",
+ "type": "module",
+ "types": "./dist-js/index.d.ts",
+ "main": "./dist-js/index.cjs",
+ "module": "./dist-js/index.js",
+ "exports": {
+ "types": "./dist-js/index.d.ts",
+ "import": "./dist-js/index.js",
+ "require": "./dist-js/index.cjs"
+ },
+ "files": [
+ "dist-js",
+ "README.md"
+ ],
+ "scripts": {
+ "build": "rollup -c",
+ "prepublishOnly": "pnpm build",
+ "pretest": "pnpm build"
+ },
+ "dependencies": {
+ "@tauri-apps/api": "^2.0.0"
+ },
+ "devDependencies": {
+ "@rollup/plugin-typescript": "^12.0.0",
+ "rollup": "^4.9.6",
+ "typescript": "^5.3.3",
+ "tslib": "^2.6.2"
+ }
+}
diff --git a/permissions/default.toml b/permissions/default.toml
new file mode 100644
index 0000000..cc5a76f
--- /dev/null
+++ b/permissions/default.toml
@@ -0,0 +1,3 @@
+[default]
+description = "Default permissions for the plugin"
+permissions = ["allow-ping"]
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 0000000..8b4768f
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,31 @@
+import { readFileSync } from 'node:fs'
+import { dirname, join } from 'node:path'
+import { cwd } from 'node:process'
+import typescript from '@rollup/plugin-typescript'
+
+const pkg = JSON.parse(readFileSync(join(cwd(), 'package.json'), 'utf8'))
+
+export default {
+ input: 'guest-js/index.ts',
+ output: [
+ {
+ file: pkg.exports.import,
+ format: 'esm'
+ },
+ {
+ file: pkg.exports.require,
+ format: 'cjs'
+ }
+ ],
+ plugins: [
+ typescript({
+ declaration: true,
+ declarationDir: dirname(pkg.exports.import)
+ })
+ ],
+ external: [
+ /^@tauri-apps\/api/,
+ ...Object.keys(pkg.dependencies || {}),
+ ...Object.keys(pkg.peerDependencies || {})
+ ]
+}
diff --git a/src/commands.rs b/src/commands.rs
new file mode 100644
index 0000000..a0bee4a
--- /dev/null
+++ b/src/commands.rs
@@ -0,0 +1,13 @@
+use tauri::{AppHandle, command, Runtime};
+
+use crate::models::*;
+use crate::Result;
+use crate::BluclasExt;
+
+#[command]
+pub(crate) async fn ping(
+ app: AppHandle,
+ payload: PingRequest,
+) -> Result {
+ app.bluclas().ping(payload)
+}
diff --git a/src/desktop.rs b/src/desktop.rs
new file mode 100644
index 0000000..2416875
--- /dev/null
+++ b/src/desktop.rs
@@ -0,0 +1,22 @@
+use serde::de::DeserializeOwned;
+use tauri::{plugin::PluginApi, AppHandle, Runtime};
+
+use crate::models::*;
+
+pub fn init(
+ app: &AppHandle,
+ _api: PluginApi,
+) -> crate::Result> {
+ Ok(Bluclas(app.clone()))
+}
+
+/// Access to the bluclas APIs.
+pub struct Bluclas(AppHandle);
+
+impl Bluclas {
+ pub fn ping(&self, payload: PingRequest) -> crate::Result {
+ Ok(PingResponse {
+ value: payload.value,
+ })
+ }
+}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..895220d
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,21 @@
+use serde::{ser::Serializer, Serialize};
+
+pub type Result = std::result::Result;
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error(transparent)]
+ Io(#[from] std::io::Error),
+ #[cfg(mobile)]
+ #[error(transparent)]
+ PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
+}
+
+impl Serialize for Error {
+ fn serialize(&self, serializer: S) -> std::result::Result
+ where
+ S: Serializer,
+ {
+ serializer.serialize_str(self.to_string().as_ref())
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..fc82184
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,48 @@
+use tauri::{
+ plugin::{Builder, 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::Bluclas;
+#[cfg(mobile)]
+use mobile::Bluclas;
+
+/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the bluclas APIs.
+pub trait BluclasExt {
+ fn bluclas(&self) -> &Bluclas;
+}
+
+impl> crate::BluclasExt for T {
+ fn bluclas(&self) -> &Bluclas {
+ self.state::>().inner()
+ }
+}
+
+/// Initializes the plugin.
+pub fn init() -> TauriPlugin {
+ Builder::new("bluclas")
+ .invoke_handler(tauri::generate_handler![commands::ping])
+ .setup(|app, api| {
+ #[cfg(mobile)]
+ let bluclas = mobile::init(app, api)?;
+ #[cfg(desktop)]
+ let bluclas = desktop::init(app, api)?;
+ app.manage(bluclas);
+ Ok(())
+ })
+ .build()
+}
diff --git a/src/mobile.rs b/src/mobile.rs
new file mode 100644
index 0000000..a37ab08
--- /dev/null
+++ b/src/mobile.rs
@@ -0,0 +1,34 @@
+use serde::de::DeserializeOwned;
+use tauri::{
+ plugin::{PluginApi, PluginHandle},
+ AppHandle, Runtime,
+};
+
+use crate::models::*;
+
+#[cfg(target_os = "ios")]
+tauri::ios_plugin_binding!(init_plugin_bluclas);
+
+// 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("", "ExamplePlugin")?;
+ #[cfg(target_os = "ios")]
+ let handle = api.register_ios_plugin(init_plugin_bluclas)?;
+ Ok(Bluclas(handle))
+}
+
+/// Access to the bluclas APIs.
+pub struct Bluclas(PluginHandle);
+
+impl Bluclas {
+ pub fn ping(&self, payload: PingRequest) -> crate::Result {
+ self
+ .0
+ .run_mobile_plugin("ping", payload)
+ .map_err(Into::into)
+ }
+}
diff --git a/src/models.rs b/src/models.rs
new file mode 100644
index 0000000..1b53e9e
--- /dev/null
+++ b/src/models.rs
@@ -0,0 +1,13 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PingRequest {
+ pub value: Option,
+}
+
+#[derive(Debug, Clone, Default, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PingResponse {
+ pub value: Option,
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..0591122
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "compilerOptions": {
+ "target": "es2021",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "skipLibCheck": true,
+ "strict": true,
+ "noUnusedLocals": true,
+ "noImplicitAny": true,
+ "noEmit": true
+ },
+ "include": ["guest-js/*.ts"],
+ "exclude": ["dist-js", "node_modules"]
+}