Core Methods

initialize()

PntaFlutter.initialize(String projectId, {
  Map<String, dynamic>? metadata,
  bool registerDevice = true,
  bool autoHandleLinks = false,
  bool showSystemUI = false,
})
Initializes the plugin and optionally registers the device. When registerDevice: true (default), this method will prompt the user for notification permission and register the device with PNTA. Use registerDevice: false for delayed registration if you don’t want to prompt the user immediately. Parameters:
  • projectId: Your PNTA project ID (format: prj_XXXXXXXXX)
  • metadata (optional): Device metadata as key-value pairs
  • registerDevice (optional): Whether to register device immediately. Default: true
  • autoHandleLinks (optional): Automatically handle link_to URLs when notifications are tapped from background/terminated state. Default: false
  • showSystemUI (optional): Show system notification banner/sound when app is in foreground. Default: false
Returns: Future<void> Examples:
lib/main.dart
// Minimal - handles everything automatically
await PntaFlutter.initialize('prj_XXXXXXXXX');

// With metadata and configuration
await PntaFlutter.initialize(
  'prj_XXXXXXXXX',
  metadata: {
    'user_id': '123',
    'user_email': '[email protected]',
  },
  autoHandleLinks: true,  // Optional: enable auto-handling of links
  showSystemUI: true,     // Optional: show system UI in foreground
);

// Delayed registration scenario
await PntaFlutter.initialize(
  'prj_XXXXXXXXX',
  metadata: {
    'user_id': '123',
    'user_email': '[email protected]',
  },
  registerDevice: false,  // Don't register immediately
  autoHandleLinks: true,
);
// Register later with registerDevice()

registerDevice()

PntaFlutter.registerDevice()
Registers the device with your PNTA project using metadata from initialize(). Only needed when using delayed registration (when initialize() was called with registerDevice: false). Returns: Future<void> Example:
lib/main.dart
// First initialize with metadata but don't register
await PntaFlutter.initialize(
  'prj_XXXXXXXXX',
  metadata: {
    'user_id': '123',
    'user_email': '[email protected]',
  },
  registerDevice: false,
);

// Later, register when ready (uses stored metadata)
await PntaFlutter.registerDevice();

// Get device token after registration
final token = PntaFlutter.deviceToken;
if (token != null) {
  print('Device registered with token: $token');
}
Must call initialize() first. Only use this method when you initialized with registerDevice: false.

updateMetadata()

PntaFlutter.updateMetadata(Map<String, dynamic> metadata)
Updates device metadata without re-registering. Parameters:
  • metadata: Updated metadata as key-value pairs
Returns: Future<void> Example:
lib/main.dart
await PntaFlutter.updateMetadata({
  'last_active': DateTime.now().toIso8601String(),
});
PntaFlutter.handleLink(String link)
Manually handles a link using the plugin’s routing logic. Parameters:
  • link: The link to handle
Returns: void Example:
lib/main.dart
PntaFlutter.handleLink('/profile');
PntaFlutter.handleLink('https://example.com');

Properties

deviceToken

PntaFlutter.deviceToken
Gets the current device token after successful initialization or registration. Type: String? Returns: Device token string if registration was successful, null otherwise. Example:
lib/main.dart
await PntaFlutter.initialize('prj_XXXXXXXXX');

final token = PntaFlutter.deviceToken;
if (token != null) {
  print('Device token: $token');
} else {
  print('Device registration failed or not completed');
}
PntaFlutter.navigatorKey
Global navigator key for internal route navigation. Must be assigned to your MaterialApp. Type: GlobalKey<NavigatorState> Example:
lib/main.dart
MaterialApp(
  navigatorKey: PntaFlutter.navigatorKey,
  // ... rest of your app
)

foregroundNotifications

PntaFlutter.foregroundNotifications
Stream of notification payloads received when app is in foreground. Type: Stream<Map<String, dynamic>> Payload Structure: Both iOS and Android send identical flat payload structures:
{
  "title": "Rain expected this afternoon",
  "body": "Showers from 2–5 PM in your area...",
  "link_to": "https://example.com/weather",
  "custom_field": "custom_value"
}
Example:
lib/main.dart
PntaFlutter.foregroundNotifications.listen((payload) {
  final title = payload['title'];
  final body = payload['body'];
  final link = payload['link_to'];
  
  print('Received: $title');

  // Show custom UI
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('$title: $body')),
  );
});

onNotificationTap

PntaFlutter.onNotificationTap
Stream of notification payloads when user taps a notification from background/terminated state. Type: Stream<Map<String, dynamic>> Payload Structure: Contains the link_to field and any custom data fields. System fields (title, body) are not available on Android due to platform limitations.
{
  "link_to": "https://example.com/weather"
}
Example:
lib/main.dart
PntaFlutter.onNotificationTap.listen((payload) {
  print('User tapped notification: $payload');
  
  // Access link_to field (available on both platforms)
  final linkTo = payload['link_to'] as String?;
  
  // Track analytics, navigate to specific screen, etc.
});
The plugin handles notification links automatically using smart URL detection:
  • External URLs (with scheme) → Opens in system browser/apps
    • Examples: https://example.com, mailto:[email protected], tel:+1234567890, sms:+1234567890
    • Works automatically with no additional configuration required
  • Internal routes (without scheme) → Navigates using Flutter’s Navigator
    • Examples: /profile, /settings, /dashboard
    • Requires navigatorKey setup (covered in Quick Start)

Implementing Notification Listeners

App-Level

Global listeners in main.dart. No disposal needed since the app doesn’t get disposed.
void main() async {
  await PntaFlutter.initialize('prj_XXXXXXXXX');

  PntaFlutter.foregroundNotifications.listen((payload) {
    print('Got notification: ${payload['title']}');
  });

  runApp(MyApp());
}

Widget-Level

Listeners in StatefulWidgets. Disposal required to prevent memory leaks.
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  StreamSubscription? _sub;

  @override
  void initState() {
    super.initState();
    _sub = PntaFlutter.foregroundNotifications.listen((payload) {
      // Handle notification
    });
  }

  @override
  void dispose() {
    _sub?.cancel(); // Required to prevent memory leaks
    super.dispose();
  }
}