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': 'user@example.com',
  },
  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': 'user@example.com',
  },
  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': 'user@example.com',
  },
  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:test@example.com, 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();
  }
}