Skip to main content

Native Widgets

Shipnative includes preconfigured native widgets for both iOS and Android platforms, with seamless Supabase integration for real-time data display.

Overview

Widgets allow users to view key information from your app directly on their home screen without opening the app. Shipnative provides:
  • iOS Widgets - Built with SwiftUI, supporting all widget sizes
  • Android Widgets - Built with Kotlin, supporting all widget sizes
  • Supabase Integration - Automatic data fetching with authentication
  • Easy Styling - Theme-aware widgets that match your app design
  • Feature Flag - Easily enable/disable widgets via configuration

Quick Start

1. Enable Widgets

Widgets are disabled by default. To enable them, add to your .env file (or run yarn setup and choose Widgets):
Finding your Apple Team ID: Open Xcode, go to Preferences → Accounts, select your Apple ID, and look for your team. The Team ID is a 10-character alphanumeric string. You can also find it in your Xcode project under Signing & Capabilities after selecting a team.
Or set it in your environment:

2. Install Dependencies

The widget package is already included in package.json. If you need to reinstall:

3. Run Prebuild

Widgets require native code, so you need to run prebuild:
This will generate the native iOS and Android projects with widget extensions.

4. Build and Run

Widget Structure

Widgets are located in app/widgets/:

Using Widgets in Your App

Fetching Widget Data

Use the useWidgetData hook to fetch data for widgets:

Widget Service

The widget service handles secure data fetching with caching:

Supabase Integration

Sharing Session Tokens

Widgets need access to Supabase session tokens to fetch authenticated data. The app automatically shares tokens via:
  • iOS: App Groups (UserDefaults)
  • Android: SharedPreferences

Setting Up App Groups (iOS)

  1. Run yarn setup → enable Widgets → enter your App Group when prompted (saved as APP_GROUP_IDENTIFIER).
  2. In Xcode, select your app target
  3. Go to “Signing & Capabilities”
  4. Add “App Groups” capability
  5. Ensure the group matches APP_GROUP_IDENTIFIER (default: group.<bundleId>). The widget derives the App Group from the bundle ID if no override is set.

Data Fetching in Widgets

Widgets fetch data directly from Supabase using the REST API: iOS (Swift):
Android (Kotlin):

Styling Widgets

iOS Widget Styling

Widgets use SwiftUI with theme colors:

Android Widget Styling

Widgets use XML layouts with theme colors:
Update colors in example_widget.xml to match your app theme.

Security Best Practices

1. Row Level Security (RLS)

Enable RLS policies in Supabase for widget-accessible tables:

2. Token Management

  • Store session tokens securely in App Groups/SharedPreferences
  • Tokens are automatically refreshed by the main app
  • Widgets use read-only access to tokens

3. Data Validation

Always validate data before displaying in widgets:

4. Rate Limiting

Widget updates are rate-limited to prevent excessive API calls:
  • Minimum 5 minutes between updates
  • 15-minute cache duration
  • Maximum 10 cached items

Creating Custom Widgets

iOS Widget

  1. Create a new Swift file in app/widgets/ios/
  2. Implement TimelineProvider protocol
  3. Create SwiftUI view for widget content
  4. Register widget in ExampleWidget.swift
Example structure:

Android Widget

  1. Create a new Kotlin file in app/widgets/android/
  2. Extend AppWidgetProvider
  3. Create XML layout in res/layout/
  4. Register widget in widget_info.xml
Example structure:

Troubleshooting

Widget Not Showing

  1. Check feature flag: Ensure EXPO_PUBLIC_ENABLE_WIDGETS=true
  2. Run prebuild: Widgets require native code generation
  3. Check logs: Look for widget-related errors in Xcode/Android Studio

Data Not Loading

  1. Check Supabase config: Verify URL and key are set
  2. Check session token: Ensure user is authenticated
  3. Check RLS policies: Widgets need appropriate permissions
  4. Check network: Widgets need internet access

Build Errors

  1. iOS: Check App Group identifier matches in app and widget
  2. Android: Check package name matches in widget files
  3. Missing files: Ensure all widget files are in correct locations

Examples

Displaying User Profile

Displaying Recent Posts

API Reference

useWidgetData Hook

Options:
  • table: string - Supabase table name
  • select?: string - Columns to select (default: ”*”)
  • filters?: Record<string, any> - Filter conditions
  • limit?: number - Maximum rows (default: 10)
  • orderBy?: { column: string; ascending?: boolean } - Sort order
  • requireAuth?: boolean - Require authentication (default: false)
  • cacheKey?: string - Custom cache key
  • refreshInterval?: number - Auto-refresh interval in ms
  • enabled?: boolean - Enable/disable hook (default: true)
Returns:
  • data: T | null - Fetched data
  • loading: boolean - Loading state
  • error: Error | null - Error if any
  • refetch: () => Promise<void> - Manual refresh
  • clearCache: () => void - Clear cache
  • config: WidgetConfig - Widget configuration

Widget Service

Next Steps