diff --git a/CHANGELOG.md b/CHANGELOG.md index 41cc7d8..8d080ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ -## 0.0.1 +# Changelog -* TODO: Describe initial release. +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.0.2] - 2024-09-08 + +### Added +- Comprehensive dartdoc documentation for all public APIs +- Detailed README with usage examples and API reference +- MIT License +- Better error handling and method signatures +- Support for notification actions and remote input + +### Changed +- Improved code style and consistency +- Removed debug print statements from production code +- Fixed inconsistent Map initialization patterns +- Cleaned up commented code +- Improved toString() method formatting +- Updated example documentation + +### Fixed +- Removed unnecessary 'new' keyword usage +- Fixed mixed language comments +- Improved code documentation and comments + +## [0.0.1] - Initial Release + +### Added +- Basic notification listening capability for Android +- Remote input support for replying to notifications +- Notification action triggering +- Platform channel communication setup +- Example application demonstrating core features diff --git a/LICENSE b/LICENSE index ba75c69..d235328 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1,21 @@ -TODO: Add your license here. +MIT License + +Copyright (c) 2024 Remote Input Plugin Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a361d30..426a778 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,177 @@ -# remote_input +# Remote Input Plugin -A new flutter plugin project. +A Flutter plugin that provides notification listener capabilities with remote input functionality for Android applications. This plugin allows your Flutter app to listen to incoming notifications and interact with them, including replying to notifications that support remote input. -## Getting Started +## Features -This project is a starting point for a Flutter -[plug-in package](https://flutter.dev/developing-packages/), -a specialized package that includes platform-specific implementation code for -Android and/or iOS. +- πŸ”” Listen to incoming Android notifications in real-time +- πŸ’¬ Reply to notifications that support remote input (e.g., messaging apps) +- ⚑ Trigger notification actions programmatically +- πŸ“± Get available actions for notifications +- 🎯 Filter and process notification events -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## Platform Support + +| Platform | Support | +|----------|---------| +| Android | βœ… Full support | +| iOS | ❌ Not supported | + +## Installation + +Add this to your package's `pubspec.yaml` file: + +```yaml +dependencies: + remote_input: ^0.0.2 +``` + +Run the following command to install the package: + +```bash +flutter pub get +``` + +## Permissions + +This plugin requires notification access permission on Android. The user must manually enable notification access for your app in the device settings. + +### Android Setup + +Add the following permission to your `android/app/src/main/AndroidManifest.xml`: + +```xml + +``` + +## Usage + +### Basic Example + +```dart +import 'package:remote_input/remote_input.dart'; +import 'dart:async'; + +class NotificationListener { + late RemoteInput _remoteInput; + late StreamSubscription _subscription; + + void startListening() { + _remoteInput = RemoteInput(); + + try { + _subscription = _remoteInput.notificationStream.listen((event) { + print('Received notification from: ${event.packageName}'); + print('Title: ${event.packageTitle}'); + print('Message: ${event.packageMessage}'); + print('Supports reply: ${event.withRemoteInput}'); + }); + } on NotificationException catch (e) { + print('Error: $e'); + } + } + + void stopListening() { + _subscription.cancel(); + } +} +``` + +### Replying to Notifications + +```dart +// Reply to a notification that supports remote input +void replyToNotification(String notificationId, String replyText) async { + try { + bool success = await RemoteInput.remoteReply(replyText, notificationId); + if (success) { + print('Reply sent successfully'); + } else { + print('Failed to send reply'); + } + } catch (e) { + print('Error sending reply: $e'); + } +} +``` + +### Triggering Notification Actions + +```dart +// Get available actions for a notification +void getNotificationActions(String notificationId) async { + List actions = await RemoteInput.getNotificationActions(notificationId); + print('Available actions: $actions'); +} + +// Trigger a specific action +void triggerAction(String notificationId, int actionIndex) async { + bool success = await RemoteInput.triggerAction(notificationId, actionIndex); + if (success) { + print('Action triggered successfully'); + } +} +``` + +## API Reference + +### Classes + +#### `RemoteInput` +Main class providing notification listening and interaction capabilities. + +**Static Methods:** +- `Future get platformVersion` - Gets the platform version +- `Future remoteReply(String text, String id)` - Sends a reply to a notification +- `Future triggerAction(String notificationId, int actionIndex)` - Triggers a notification action +- `Future> getNotificationActions(String notificationId)` - Gets available actions + +**Instance Properties:** +- `Stream get notificationStream` - Stream of incoming notifications + +#### `NotificationEvent` +Represents a notification event with all relevant data. + +**Properties:** +- `String id` - Unique notification identifier +- `String packageName` - Source app package name +- `String packageTitle` - Notification title +- `String packageMessage` - Notification message content +- `bool withRemoteInput` - Whether the notification supports replies +- `String? remoteInputSymbol` - Remote input symbol/hint +- `List actions` - Available actions + +#### `NotificationAction` +Represents an action available on a notification. + +**Properties:** +- `int index` - Action index +- `String title` - Action title/label + +#### `NotificationException` +Exception thrown when notification operations fail. + +## Example App + +See the [example](example/) directory for a complete demonstration of the plugin's capabilities, including: + +- Setting up notification listening +- Displaying incoming notifications +- Replying to notifications +- Managing notification actions + +## Important Notes + +1. **Permissions**: Users must manually grant notification access permission in Android settings +2. **Android Only**: This plugin only works on Android devices +3. **Background Processing**: Consider the app's lifecycle when implementing notification listening +4. **Testing**: Use real messaging apps to test remote input functionality + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/example/README.md b/example/README.md index ea584e6..71b981e 100644 --- a/example/README.md +++ b/example/README.md @@ -1,16 +1,73 @@ -# remote_input_example +# Remote Input Plugin Example -Demonstrates how to use the remote_input plugin. +This example demonstrates how to use the `remote_input` plugin to listen to Android notifications and interact with them. -## Getting Started +## Features Demonstrated -This project is a starting point for a Flutter application. +- πŸ“± **Notification Listening**: Real-time monitoring of incoming notifications +- πŸ’¬ **Remote Replies**: Send replies to notifications that support it (e.g., messaging apps) +- ⚑ **Action Triggering**: Execute notification actions programmatically +- 🎯 **Event Filtering**: Process and display notification data -A few resources to get you started if this is your first Flutter project: +## Setup -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +1. **Grant Notification Access**: + - Go to Settings > Apps > [Your App] > Permissions + - Enable "Notification access" for this app + - This is required for the plugin to work -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +2. **Run the Example**: + ```bash + flutter run + ``` + +## How to Use + +1. **Start Listening**: Tap the play button to begin monitoring notifications +2. **Receive Notifications**: Send yourself messages from apps like WhatsApp, Telegram, or SMS +3. **View Events**: See incoming notifications listed in the app +4. **Reply**: Tap the reply icon on notifications that support remote input +5. **Stop Listening**: Tap the stop button to pause monitoring + +## Code Structure + +- `main.dart`: Contains the main application logic +- `MyApp`: Main app widget with notification stream handling +- `ReplyDialog`: Dialog for composing replies to notifications + +## Key Components + +### Notification Stream +```dart +_subscription = _remoteInput.notificationStream.listen(onData); +``` + +### Reply Functionality +```dart +RemoteInput.remoteReply(textEditingController.text, id) +``` + +### Event Processing +```dart +void onData(NotificationEvent event) { + setState(() { + _log.add(event); + }); +} +``` + +## Testing + +To test the example: + +1. Install messaging apps (WhatsApp, Telegram, etc.) +2. Start the example app and begin listening +3. Send yourself messages from another device +4. Observe notifications appearing in the app +5. Try replying to supported notifications + +## Requirements + +- Android device (iOS not supported) +- Notification access permission +- Messaging apps for testing remote input functionality diff --git a/lib/remote_input.dart b/lib/remote_input.dart index 85da089..5de897f 100644 --- a/lib/remote_input.dart +++ b/lib/remote_input.dart @@ -3,9 +3,11 @@ import 'dart:convert'; import 'package:flutter/services.dart'; import 'dart:io' show Platform; +/// Exception thrown when notification operations fail class NotificationException implements Exception { - String _cause; + final String _cause; + /// Creates a NotificationException with the given cause NotificationException(this._cause); @override @@ -14,15 +16,21 @@ class NotificationException implements Exception { } } +/// Represents an action available on a notification class NotificationAction { + /// The index of this action in the notification's action list final int index; + + /// The title/label of this action final String title; + /// Creates a NotificationAction with the given index and title NotificationAction({ required this.index, required this.title, }); + /// Creates a NotificationAction from a map representation factory NotificationAction.fromMap(Map map, int index) { return NotificationAction( index: index, @@ -30,6 +38,7 @@ class NotificationAction { ); } + /// Converts this NotificationAction to a map representation Map toMap() { return { 'index': index, @@ -43,15 +52,30 @@ class NotificationAction { } } +/// Represents a notification event received from the system class NotificationEvent { - String id; //id is timestamp (millisecondsSinceEpoch) + /// Unique identifier for this notification (timestamp in milliseconds since epoch) + String id; + + /// Package name of the app that posted this notification String packageName; + + /// Title of the notification String packageTitle; + + /// Message content of the notification String packageMessage; + + /// Whether this notification supports remote input (reply functionality) bool withRemoteInput; + + /// Symbol or text associated with remote input functionality String? remoteInputSymbol; + + /// List of actions available on this notification List actions; + /// Creates a NotificationEvent with the given parameters NotificationEvent({ required this.id, required this.packageName, @@ -62,6 +86,7 @@ class NotificationEvent { this.actions = const [], }); + /// Creates a NotificationEvent from a map representation factory NotificationEvent.fromMap(Map map) { String id = map['id']; String name = map['packageName']; @@ -69,7 +94,7 @@ class NotificationEvent { title = title.split('@')[0]; String message = map['packageMessage']; final remoteInputSymbol = map['remoteInputSymbol']; - bool withRemoteInput = remoteInputSymbol != null ? true : false; + bool withRemoteInput = remoteInputSymbol != null; List actions = []; if (map['actions'] != null) { for (var i = 0; i < map['actions'].length; i++) { @@ -88,6 +113,7 @@ class NotificationEvent { ); } + /// Converts this NotificationEvent to a map representation Map toMap() { return { 'id': id, @@ -100,60 +126,80 @@ class NotificationEvent { }; } + /// Converts this NotificationEvent to a JSON string String toJson() { - Map map = Map(); - map['id'] = id; - // map['2'] = packageName; - map['title'] = packageTitle; - map['message'] = packageMessage; - map['remote_input'] = withRemoteInput; + final map = { + 'id': id, + 'title': packageTitle, + 'message': packageMessage, + 'remote_input': withRemoteInput, + }; return jsonEncode(map); } + /// Converts this NotificationEvent to a watch-compatible string format + /// Truncates message to 128 characters for watch display String toWatchString() { - Map map = Map(); - map['id'] = id; - map['title'] = packageTitle; - if (packageMessage.length > 128) { - // split packageMessage to 128 characters - map['message'] = packageMessage.substring(0, 128); - } else { - map['message'] = packageMessage; - } - map['reply'] = withRemoteInput; + final map = { + 'id': id, + 'title': packageTitle, + 'message': packageMessage.length > 128 + ? packageMessage.substring(0, 128) + : packageMessage, + 'reply': withRemoteInput, + }; return jsonEncode(map); - } // For Watch + } @override String toString() { - return "ι€šηŸ₯δΊ‹δ»Ά Notification Event \n - ID: $id - Package Name: $packageName \n - Package Title: $packageTitle \n - Package Message: $packageMessage - Remote Input: $remoteInputSymbol"; + return "Notification Event\n - ID: $id\n - Package Name: $packageName\n - Package Title: $packageTitle\n - Package Message: $packageMessage\n - Remote Input: $remoteInputSymbol"; } } +/// Creates a NotificationEvent from raw data received from platform channels NotificationEvent _notificationEvent(dynamic data) { - print('NotificationEvent: $data'); - return new NotificationEvent.fromMap(data); + return NotificationEvent.fromMap(data); } +/// A Flutter plugin for listening to Android notifications and interacting with them +/// +/// This plugin provides functionality to: +/// - Listen to incoming notifications +/// - Reply to notifications that support remote input +/// - Trigger notification actions +/// - Get available notification actions class RemoteInput { static const MethodChannel _methodChannel = - const MethodChannel('flutter.io/remote_input/methodChannel'); + MethodChannel('flutter.io/remote_input/methodChannel'); static const EventChannel _eventChannel = - const EventChannel('flutter.io/remote_input/eventChannel'); + EventChannel('flutter.io/remote_input/eventChannel'); + /// Gets the platform version static Future get platformVersion async { final String version = await _methodChannel.invokeMethod('getPlatformVersion'); return version; } + /// Sends a reply to a notification that supports remote input + /// + /// [text] The reply text to send + /// [id] The notification ID to reply to + /// + /// Returns true if the reply was sent successfully static Future remoteReply(String text, String id) async { final bool isSuccessful = await _methodChannel.invokeMethod('remoteInput', - {"text": text, "id": id}); // Reply to the notification with id + {"text": text, "id": id}); return isSuccessful; } - /// Trigger a specific notification action by index + /// Triggers a specific notification action by index + /// + /// [notificationId] The ID of the notification + /// [actionIndex] The index of the action to trigger + /// + /// Returns true if the action was triggered successfully static Future triggerAction( String notificationId, int actionIndex) async { final bool isSuccessful = await _methodChannel.invokeMethod( @@ -161,7 +207,11 @@ class RemoteInput { return isSuccessful; } - /// Get all available actions for a notification + /// Gets all available actions for a notification + /// + /// [notificationId] The ID of the notification + /// + /// Returns a list of action titles static Future> getNotificationActions( String notificationId) async { final List actions = await _methodChannel @@ -171,6 +221,11 @@ class RemoteInput { late Stream _notificationStream; + /// Stream of incoming notification events + /// + /// Note: This functionality is only available on Android + /// + /// Throws [NotificationException] if called on non-Android platforms Stream get notificationStream { if (Platform.isAndroid) { _notificationStream = _eventChannel diff --git a/pubspec.yaml b/pubspec.yaml index 231d29a..24e59d7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,8 +1,8 @@ name: remote_input -description: notification listener with remote input capability +description: A Flutter plugin for Android notification listening with remote input capabilities. Listen to notifications, reply to messages, and trigger notification actions. version: 0.0.2 -author: -homepage: +author: Remote Input Plugin Contributors +homepage: https://github.com/shixin627/Remotely_Input_Plugin environment: sdk: ">=2.12.0 <3.0.0"