Prerequisites

Make sure you’ve completed the Platform Setup for iOS and Android before proceeding.

How to Use

Add one line to your app’s main() function:

lib/main.dart
import 'package:pnta_flutter/pnta_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // That's it! Handles permissions and registration automatically
  await PntaFlutter.initialize('prj_XXXXXXXXX');

  runApp(MyApp());
}

Get your project ID from your PNTA Dashboard settings.

That’s it! Your app now receives push notifications.


Advanced Usage

Configuration Options

You can configure optional parameters for more control:

lib/main.dart
await PntaFlutter.initialize(
  'prj_XXXXXXXXX',
  metadata: {
    'user_id': '123',
    'user_email': 'user@example.com',
  },
  registerDevice: false,  // Optional: delay registration until later
  autoHandleLinks: true,  // Optional: enable auto-handling of links
  showSystemUI: true,     // Optional: show system UI when app is in foreground
);

// Get device token after initialization/registration
final deviceToken = PntaFlutter.deviceToken;
if (deviceToken != null) {
  print('Device registered: $deviceToken');
}

Delayed Registration

If you need to register the device later (e.g., after user login), use delayed registration:

lib/main.dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize with metadata but don't register yet
  await PntaFlutter.initialize(
    'prj_XXXXXXXXX',
    metadata: {
      'user_id': '123',
      'user_email': 'user@example.com',
    },
    registerDevice: false,  // Don't register immediately
  );

  runApp(MyApp());
}

void _registerAfterLogin() async {
  // Register device (uses metadata from initialize)
  await PntaFlutter.registerDevice();
}

Best Practice: Consider delayed registration for better opt-in rates. Prompt users for notifications during onboarding or after signup when they understand the value.

Custom Notification Handling

Foreground Notifications

When your app is open and active, notifications arrive silently by default (no system banner). Use this to show custom UI like snackbars or dialogs:

lib/main.dart
PntaFlutter.foregroundNotifications.listen((payload) {
  print('Received foreground notification: ${payload['title']}');

  // Show custom UI (snackbar, dialog, etc.)
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('${payload['title']}: ${payload['body']}')),
  );

  // Manually handle links if needed
  final link = payload['link_to'] as String?;
  if (link != null && link.isNotEmpty) {
    PntaFlutter.handleLink(link);
  }
});

iOS: Set showSystemUI: true to display the standard notification banner when your app is in the foreground.

Android: Set showSystemUI: true to make notifications appear in the notification panel. By default, Android foreground notifications are silent and don’t appear in the panel. You’ll need to handle in-app UI using the listener above.

Background/Terminated Notifications

When users tap notifications while your app is in background or closed:

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, show specific screen, etc.
  // Links are auto-handled if autoHandleLinks is set to true
});

Set autoHandleLinks: true to automatically handle notification links. External URLs open in the browser, internal routes navigate within your app (requires navigator key setup).

Deep Linking Setup

For notifications that navigate to specific pages in your app:

lib/main.dart
MaterialApp(
  navigatorKey: PntaFlutter.navigatorKey, // Required for internal route navigation
  // ... rest of your app
)

Only needed if your notifications contain internal routes like /profile. External URLs with schemes (https://, mailto:, tel:, sms:) work automatically with no configuration.

Complete Example

This example shows multiple optional features. Remember: most apps only need the one-liner from “How to Use” above.

lib/main.dart
import 'package:flutter/material.dart';
import 'package:pnta_flutter/pnta_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize plugin - handles everything automatically
  await PntaFlutter.initialize(
    'prj_XXXXXXXXX',
    metadata: {
      'user_id': '123',
      'user_email': 'user@example.com',
    },
    autoHandleLinks: true,  // Optional: enable auto-handling of links
  );

  // App-level listeners - work everywhere, no disposal needed
  PntaFlutter.foregroundNotifications.listen((payload) {
    print('Foreground notification: ${payload['title']}');
  });

  PntaFlutter.onNotificationTap.listen((payload) {
    print('Notification tapped: ${payload['link_to']}');
  });

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: PntaFlutter.navigatorKey, // Required for deep linking
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('PNTA Example')),
      body: Center(child: Text('Ready for notifications!')),
    );
  }
}