feature/extend-tauri-generated-xcode-project-for-tvos-target
md 340 lines 8.11 KB
Rendered Raw
1 # Tauri Plugin iOS Window
2
3 A Tauri plugin for opening modal windows with WebView on iOS, perfect for OAuth flows and external authentication.
4
5 ## Features
6
7 - 🪟 **Modal Presentation** - Opens as popover on iPad, modal on iPhone
8 - 🎨 **Customizable UI** - Set custom titles, follows Apple HIG
9 - 📊 **Progress Tracking** - Built-in loading indicator and progress bar
10 - 🔄 **Navigation** - Back/forward swipe gestures enabled
11 -**Native Feel** - Follows iOS Human Interface Guidelines
12 - 🔐 **OAuth Ready** - Perfect for Sign in with Apple, OAuth flows
13
14 ## Installation
15
16 ```bash
17 # Install the plugin
18 npm install tauri-plugin-ios-window-api
19 # or
20 yarn add tauri-plugin-ios-window-api
21 # or
22 pnpm add tauri-plugin-ios-window-api
23 ```
24
25 Add the plugin to your Tauri app's `src-tauri/Cargo.toml`:
26
27 ```toml
28 [dependencies]
29 tauri-plugin-ios-window = { git = "https://github.com/yourusername/tauri-plugin-ios-window" }
30 ```
31
32 Register the plugin in your Tauri app's `src-tauri/src/lib.rs`:
33
34 ```rust
35 fn run() {
36 tauri::Builder::default()
37 .plugin(tauri_plugin_ios_window::init())
38 .run(tauri::generate_context!())
39 .expect("error while running tauri application");
40 }
41 ```
42
43 ## Usage
44
45 ### Basic Example
46
47 ```typescript
48 import { open } from "tauri-plugin-ios-window-api";
49
50 // Open a URL with default title
51 await open("https://example.com");
52
53 // Open with custom title
54 await open("https://example.com", "My Custom Title");
55 ```
56
57 ### OAuth Flow Example (SplitFire Pattern)
58
59 This example shows how to integrate with an OAuth provider like Sign in with Apple:
60
61 ```typescript
62 import { open } from "tauri-plugin-ios-window-api";
63
64 async function signInWithApple() {
65 try {
66 // Your OAuth configuration
67 const baseUrl = "https://splitfire.ai";
68 const redirectUri = "your-app://oauth/callback";
69
70 // Build OAuth URL
71 const oauthUrl = `${baseUrl}/synch-apple/auth?redirect_uri=${encodeURIComponent(redirectUri)}`;
72
73 // Open OAuth window
74 await open(oauthUrl, "Sign in with Apple");
75
76 // Handle the callback (implement based on your needs)
77 // Option 1: Deep link handler
78 // Option 2: Local server listener
79 // Option 3: Custom URL scheme
80
81 } catch (error) {
82 console.error("OAuth failed:", error);
83 }
84 }
85 ```
86
87 ### Complete OAuth Implementation
88
89 ```typescript
90 import { open } from "tauri-plugin-ios-window-api";
91 import { listen } from "@tauri-apps/api/event";
92
93 async function startOAuthFlow(provider: "apple" | "spotify" | "youtube") {
94 try {
95 // Start local OAuth server (Rust backend)
96 const port = await invoke("start_oauth_server");
97
98 // Configure redirect
99 const redirectUri = `http://localhost:${port}`;
100 const baseUrl = "https://splitfire.ai";
101 const oauthUrl = `${baseUrl}/synch-${provider}/auth?redirect_uri=${redirectUri}`;
102
103 // Open OAuth window
104 await open(oauthUrl, `Sign in with ${provider}`);
105
106 // Listen for OAuth callback
107 const unlisten = await listen("oauth-callback", (event) => {
108 const { code, state } = event.payload;
109
110 // Exchange code for access token
111 invoke("exchange_oauth_token", { code, provider })
112 .then((response) => {
113 console.log("OAuth successful:", response);
114 // Handle successful authentication
115 })
116 .catch((error) => {
117 console.error("Token exchange failed:", error);
118 });
119 });
120
121 } catch (error) {
122 console.error("OAuth flow failed:", error);
123 }
124 }
125 ```
126
127 ## API Reference
128
129 ### `open(url: string, title?: string): Promise<void>`
130
131 Opens a new modal window with a WebView.
132
133 **Parameters:**
134 - `url` (string, required) - The URL to open in the WebView
135 - `title` (string, optional) - Custom title for the navigation bar. Defaults to "Sign in"
136
137 **Returns:**
138 - `Promise<void>` - Resolves when the window is presented
139
140 **Example:**
141 ```typescript
142 // Basic usage
143 await open("https://example.com");
144
145 // With custom title
146 await open("https://appleid.apple.com", "Sign in with Apple");
147 ```
148
149 ### `close(): Promise<void>`
150
151 Programmatically closes the currently opened window.
152
153 **Parameters:**
154 - None
155
156 **Returns:**
157 - `Promise<void>` - Resolves when the window is dismissed
158
159 **Example:**
160 ```typescript
161 // Close the window
162 await close();
163
164 // Open and auto-close after delay
165 await open("https://example.com", "Loading...");
166 setTimeout(async () => {
167 await close();
168 }, 3000);
169 ```
170
171 ## UI/UX Features
172
173 ### Navigation Bar
174 - Clean, native iOS design
175 - Close button on leading edge (per Apple HIG)
176 - Centered title
177 - Activity indicator during loading
178 - Subtle border separator
179
180 ### Progress Indicator
181 - 2px blue progress bar
182 - Smooth animations
183 - Auto-hides when complete
184 - Tracks page load progress
185
186 ### WebView
187 - Full-screen immersive experience
188 - Back/forward swipe gestures
189 - Inline media playback
190 - Proper dark mode support
191 - Error state handling
192
193 ### Modal Presentation
194 - **iPad**: Popover (400x600)
195 - **iPhone**: Full-screen modal
196 - Smooth dismiss animations
197 - Safe area aware
198
199 ## Platform Support
200
201 - ✅ iOS (iPhone & iPad)
202 - ⚠️ Desktop (no-op, falls through to default behavior)
203 - ❌ Android (not supported)
204
205 ## Best Practices
206
207 ### OAuth Flows
208
209 1. **Use HTTPS in production**
210 ```typescript
211 const baseUrl = process.env.NODE_ENV === "production"
212 ? "https://splitfire.ai"
213 : "https://localhost:3333";
214 ```
215
216 2. **Handle redirects properly**
217 - Use custom URL schemes for mobile: `your-app://oauth/callback`
218 - Use localhost for testing: `http://localhost:8080/callback`
219 - Always encode redirect URIs
220
221 3. **Security**
222 - Use PKCE for OAuth 2.0
223 - Validate state parameters
224 - Store tokens securely
225 - Use short-lived access tokens
226
227 4. **Error Handling**
228 ```typescript
229 try {
230 await open(oauthUrl, "Sign in");
231 } catch (error) {
232 // Handle network errors
233 // Show user-friendly message
234 // Log for debugging
235 }
236 ```
237
238 ### UI/UX
239
240 1. **Use descriptive titles**
241 ```typescript
242 await open(url, "Sign in with Apple"); // ✅ Good
243 await open(url, "Sign in"); // ⚠️ Generic
244 await open(url); // ❌ Uses default
245 ```
246
247 2. **Provide feedback**
248 - Show loading states before opening
249 - Handle success/error after OAuth
250 - Give users clear next steps
251
252 3. **Test on both devices**
253 - iPad (popover experience)
254 - iPhone (modal experience)
255
256 ### Programmatic Closing
257
258 1. **After OAuth completion**
259 ```typescript
260 // Listen for OAuth callback
261 listen("oauth-callback", async (event) => {
262 // Process OAuth response
263 await handleOAuthToken(event.payload);
264
265 // Close the window
266 await close();
267 });
268 ```
269
270 2. **Timeout scenarios**
271 ```typescript
272 // Auto-close if user doesn't complete within time limit
273 await open(oauthUrl, "Sign in");
274
275 const timeout = setTimeout(async () => {
276 await close();
277 showMessage("Authentication timed out");
278 }, 60000); // 1 minute
279
280 // Clear timeout if user completes
281 listen("oauth-complete", () => clearTimeout(timeout));
282 ```
283
284 3. **Error handling**
285 ```typescript
286 try {
287 await open(url, "Sign in");
288 } catch (error) {
289 // If window fails to open, don't try to close
290 console.error("Failed to open:", error);
291 return;
292 }
293
294 // Later, close if needed
295 try {
296 await close();
297 } catch (error) {
298 // Window may already be closed by user
299 console.log("Window already closed");
300 }
301 ```
302
303 ## Example App
304
305 Check out the complete example in `examples/tauri-app`:
306
307 ```bash
308 cd examples/tauri-app
309 npm install
310 npm run tauri ios dev
311 ```
312
313 ## Development
314
315 ```bash
316 # Clone the repository
317 git clone https://github.com/yourusername/tauri-plugin-ios-window
318
319 # Install dependencies
320 npm install
321
322 # Build the plugin
323 npm run build
324
325 # Run example
326 cd examples/tauri-app
327 npm run tauri ios dev
328 ```
329
330 ## Contributing
331
332 Contributions are welcome! Please feel free to submit a Pull Request.
333
334 ## License
335
336 MIT
337
338 ## Credits
339
340 Built for [SplitFire](https://splitfire.ai) - OAuth pattern inspired by production usage.