Flutter wrapper for Channel Talk Android and iOS projects.(Unofficial)
*******************************************************************************************************
[ANDROID]
Please should change the bottom part when change version from v2.x.x to above of v3.0.0.
In AndroidManifest.xml file,
AS-IS
<service
android:name="ai.deepnatural.channel_talk.PushInterceptService"
...
TO-BE
<service
android:name="com.kuku.channel_talk_flutter.PushInterceptService"
...
*******************************************************************************************************
- Flutter 3.19 / Dart 3.3 or later is required by the Web JS interop implementation.
- Bundled SDKs: Android 13.5.0 and iOS 13.3.0 (verified on 2026-09-12).
- Channel Talk APIs are implemented for Android, iOS, and Web. The registered macOS plugin is a placeholder and does not implement those APIs.
- iOS 15.0 or later is required.
- Android
minSdkVersion21 or later is required. - The Android plugin module currently builds with
compileSdkVersion 35. - Android 13 (API 33) or later requires
POST_NOTIFICATIONSpermission for system push notifications. - The Android plugin still depends on
com.google.firebase:firebase-messaging:20.1.0. If your app pins Firebase BOM or messaging versions directly, verify the resolved dependency graph.
3.x -> 4.x- Raise the iOS deployment target to 15.0 or later before upgrading.
4.1.x -> 4.2.x- Raise Android
minSdkVersionto 21 or later before upgrading. - If your project uses an older Android Gradle Plugin, verify it is
compatible with
compileSdkVersion 35.
- Raise Android
4.2.x -> 4.3.0- Raise Flutter to 3.19 / Dart to 3.3 or later.
ChannelTalk.setPage(page: ...)still works and now also acceptsprofile. Web requires a non-null page; useresetPage()to reset it.- Custom
ChannelTalkFlutterPlatformimplementations must change theirsetPageoverride tosetPage({String? page, Map<String, dynamic>? profile}). - Web now supports
setListener,removeListener,hidePopup, andsetPreventDefaultUrlClick. - Web
boot,updateUser,addTags, andremoveTagsnow wait for the SDK callback and returnfalseon SDK failure. JS invocation errors complete the Future with an error. - Native
updateUserpreserves omitted language, tags, and marketing preferences.
See SDK compatibility audit for findings and validation.
- 작업 지침: 코드 탐색, 변경 규칙, 유지해야 할 플랫폼 계약.
- 구조와 플랫폼 차이: 파일 지도, 요청·이벤트 흐름, 데이터·오류 처리.
- 테스트·빌드 가이드: 검증 범위와 플랫폼별 실행 방법.
- 전체 문서 목록: 폴더별 안내와 SDK 호환성 점검 기록.
import 'package:channel_talk_flutter/channel_talk_flutter.dart';
void main() async {
await ChannelTalk.boot(
pluginKey: 'pluginKey', // Required
memberId: 'memberId',
memberHash: 'memberHash',
email: 'email',
name: 'name',
mobileNumber: 'mobileNumber',
avatarUrl: 'avatarUrl',
unsubscribeEmail: false,
unsubscribeTexting: false,
trackDefaultEvent: false,
hidePopup: false,
language: Language.korean,
appearance: Appearance.dark,
);
ChannelTalk.setListener((event, arguments) {
switch(event){
case ChannelTalkEvent.onShowMessenger:
print('ON_SHOW_MESSENGER');
break;
case ChannelTalkEvent.onHideMessenger:
print('ON_HIDE_MESSENGER');
break;
case ChannelTalkEvent.onChatCreated:
print('ON_CHAT_CREATED:\nchatId: $arguments');
break;
case ChannelTalkEvent.onBadgeChanged:
print('ON_BADGE_CHANGED:\n$arguments');
break;
case ChannelTalkEvent.onFollowUpChanged:
print('ON_FOLLOW_UP_CHANGED\ndata: $arguments');
break;
case ChannelTalkEvent.onUrlClicked:
print('ON_URL_CLICKED\nurl: $arguments');
break;
case ChannelTalkEvent.onPopupDataReceived:
print('ON_POPUP_DATA_RECEIVED\nevent: $arguments}');
break;
case ChannelTalkEvent.onPushNotificationClicked:
print('ON_PUSH_NOTIFICATION_CLICKED\nevent: $arguments}');
default:
break;
}
});
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FlatButton(
child: Text('Open Channel Talk'),
onPressed: () async {
await ChannelTalk.showMessenger();
},
);
}
}
See Channel Talk Android and iOS package documentation for more information.
boot() returns true only on success. To tell why a boot failed — e.g. to
retry a transient networkTimeout but give up on a permanent accessDenied —
use bootWithStatus(), which resolves to a ChannelTalkBootStatus (success,
notInitialized, networkTimeout, notAvailableVersion,
serviceUnderConstruction, requirePayment, accessDenied, unknown). It
takes the same arguments as boot() and shares the same native boot path. On
web, the SDK callback resolves to success when no error is reported, otherwise unknown.
final status = await ChannelTalk.bootWithStatus(pluginKey: 'pluginKey');
if (status != ChannelTalkBootStatus.success) {
// inspect `status` and decide whether to retry
}Set the app's iOS deployment target to 15.0 or later for both Swift Package Manager and CocoaPods.
Update info.plist.
<key>NSCameraUsageDescription</key>
<string>Accessing to camera in order to provide better user experience</string>
<key>NSMicrophoneUsageDescription</key>
<string>Accessing to microphone to record voice for video</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Accessing to photo library in order to save photos</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Accessing to photo library in order to provide better user experience</string>Both integrations currently use ChannelIOSDK 13.3.0.
The plugin installs ChannelIOSDK automatically through Swift Package Manager (SPM) or CocoaPods.
Remove any explicit pod 'ChannelIOSDK', ... entry from ios/Podfile when upgrading.
Keeping that entry with SPM causes a duplicate ChannelIOFront.framework build error.
Swift Package Manager: Flutter 3.44 and later enable SPM by default. To enable it for your app,
merge this setting into the existing flutter section of the app's pubspec.yaml:
flutter:
config:
enable-swift-package-manager: trueRun flutter pub get, then build or run the app to let Flutter integrate the Swift package.
See the Flutter SPM migration guide if your app has custom native integration.
CocoaPods: Existing CocoaPods apps can continue using the plugin's podspec. With Flutter 3.44
or later, set enable-swift-package-manager: false in the app configuration above to use CocoaPods.
Keep the Flutter installation call in ios/Podfile; no separate ChannelIOSDK pod entry is needed:
platform :ios, '15.0'
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
endAfter changing the Podfile, run flutter pub get from the app directory, then pod install
from ios/. This also applies to SPM apps that retain CocoaPods for other dependencies.
Add ChannelTalk initializing code to [project]/ios/Runner/AppDelegate.swift
import ChannelIOFront
...
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
...
ChannelIO.initialize(application)
...
}
...
- minSdkVersion 21 (Channel Talk Android SDK requires API 21+ for features to work)
- compileSdkVersion 35 is used by this plugin module
- Android 13 (API 33) or later requires
POST_NOTIFICATIONSpermission for system push notifications.
The plugin adds Channel.io's official Maven repository for io.channel artifacts.
If your app centrally manages repositories in settings.gradle, add it there too:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url 'https://maven.channel.io/maven2'
content { includeGroup 'io.channel' }
}
}
}Android supports explicit Korean, Japanese, and English SDK languages.
Language.device uses the device language during boot; in updateUser it leaves
the current language unchanged because the Android SDK has no device-language enum.
This plugin works in combination with the firebase_messaging plugin to receive Push Notifications. To set this up:
- First, implement
firebase_messagingand check if it works: https://pub.dev/packages/firebase_messaging#android-integration - Configure Firebase credentials in Channel Talk using the current FCM integration guide.
- If your app targets Android 13 or above, request notification permission before showing system pushes.
- Add the following to your
AndroidManifest.xmlfile, so incoming messages are handled by Channel Talk:
<service
android:name="com.kuku.channel_talk_flutter.PushInterceptService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
just above the closing </application> tag.
The SDK script must be loaded before calling this package. Await bootForWeb
before calling APIs that need a booted user. isBooted, sleep, and native push
notification APIs are not supported on Web.
The Web onChatCreated event has no chat ID argument, so its listener payload is null.
setPage requires a non-null page on Web. Use resetPage to reset the page
and user chat profile. The listener APIs use the SDK's global clearCallbacks;
manage Channel.io callbacks through this package when using setListener or removeListener.
Insert the following script within the tag of your HTML file(web/index.html):
<script>
(function(){var w=window;if(w.ChannelIO){return w.console.error("ChannelIO script included twice.");}var ch=function(){ch.c(arguments);};ch.q=[];ch.c=function(args){ch.q.push(args);};w.ChannelIO=ch;function l(){if(w.ChannelIOInitialized){return;}w.ChannelIOInitialized=true;var s=document.createElement("script");s.type="text/javascript";s.async=true;s.src="https://cdn.channel.io/plugin/ch-plugin-web.js";var x=document.getElementsByTagName("script")[0];if(x.parentNode){x.parentNode.insertBefore(s,x);}}if(document.readyState==="complete"){l();}else{w.addEventListener("DOMContentLoaded",l);w.addEventListener("load",l);}})();
</script>In case of Web platform, would better use bootForWeb API but we can also use boot API.
import 'package:channel_talk_flutter/channel_talk_flutter.dart';
void main() async {
await ChannelTalk.bootForWeb(
pluginKey: 'pluginKey', // Required
memberId: 'memberId',
memberHash: 'memberHash',
email: 'email',
name: 'name',
mobileNumber: '0101231234',
avatarUrl: 'avatarUrl',
customLauncherSelector: 'customLauncherSelector',
hideChannelButtonOnBoot: false,
zIndex: 10000000,
trackDefaultEvent: false,
trackUtmSource: false,
unsubscribeEmail: false,
unsubscribeTexting: false,
hidePopup: false,
appearance: Appearance.light,
language: Language.japanese,
);
...
}| API | API Description | Parameter | Type | Parameter Description | Support platforms |
|---|---|---|---|---|---|
| setListener | Set the delegate allows the reception of event callbacks from the SDK. | delegate* | ChannelTalkDelegate | Support onShowMessenger/onHideMessenger/onChatCreated/onBadgeChanged/onFollowUpChanged/onUrlClicked/onPopupDataReceived | Mobile, Web |
| removeListener | Remove the delegate allows the reception of event callbacks from the SDK.q | Mobile, Web | |||
| boot | Load the information necessary to use the SDK. | pluginKey* | String | Plugin key of Channel. | Mobile, Web |
| memberId | String? | An identifier to distinguish each member user. | |||
| memberHash | String? | A HMAC-SHA256 value of memberId. | |||
| String? | An email of a user. | ||||
| name | String? | A name of a user. | |||
| mobileNumber | String? | A mobile number of a user. | |||
| avatarUrl | String? | An avatar URL of a user. | |||
| language | Language? | A user’s language. It is valid when creating a new user. The language of the user that already exists will not change. | |||
| unsubscribeEmail | bool? | Sets whether to receive marketing messages via email. | |||
| unsubscribeTexting | bool? | Sets whether to receive marketing messages via texting (SMS, LMS) | |||
| trackDefaultEvent | bool? | Sets whether to track the default event, such as PageView. | |||
| hidePopup | bool? | Sets whether to hide popups such as marketing popup and in-app notifications. | |||
| appearance | Appearance? | Sets the appearance of SDK. | |||
| bootForWeb | Load the information necessary to use the SDK. | pluginKey* | String | Plugin key of Channel. | Web |
| memberId | String? | An identifier to distinguish each member user. | |||
| memberHash | String? | A HMAC-SHA256 value of memberId. | |||
| String? | An email of a user. | ||||
| name | String? | A name of a user. | |||
| mobileNumber | String? | A mobile number of a user. | |||
| avatarUrl | String? | An avatar URL of a user. | |||
| language | Language? | A user’s language. It is valid when creating a new user. The language of the user that already exists will not change. | |||
| unsubscribeEmail | bool? | Sets whether to receive marketing messages via email. | |||
| unsubscribeTexting | bool? | Sets whether to receive marketing messages via texting (SMS, LMS) | |||
| trackDefaultEvent | bool? | Sets whether to track the default event, such as PageView. | |||
| hidePopup | bool? | Sets whether to hide popups such as marketing popup and in-app notifications. | |||
| appearance | Appearance? | Sets the appearance of SDK. | |||
| customLauncherSelector | String? | The CSS Selector to select a custom launcher. Use this option to customize the default chat button. | |||
| hideChannelButtonOnBoot | bool? | Determines whether to hide the default chat button on boot. The default value is false. | |||
| zIndex | int? | Sets the z-index for SDK elements, such as the chat button, messenger, and marketing pop-ups. The default value is 10000000. | |||
| trackUtmSource | bool? | Determines whether to track the UTM source and referrer. The default value is true. | |||
| sleep | Disables all features except for receiving system push notifications and using the Track. | Mobile | |||
| shutdown | Disconnects the SDK from the channel. | Mobile, Web | |||
| showChannelButton | Displays the Channel button on the global screen. | Mobile, Web | |||
| hideChannelButton | Hides the Channel button on the global screen. | Mobile, Web | |||
| showMessenger | Displays the messenger. | Mobile, Web | |||
| hideMessenger | Hides the messenger. | Mobile, Web | |||
| openChat | Opens User chat. | chatId | String? | This is the chat ID. If the chatId is invalid or nil, a new user chat is opened. | Mobile, Web |
| message | String? | This is the pre-filled message in the message input field when opening a new chat. It is valid when chatId is nil. | |||
| track | Tracks the user's events. | eventName* | String | This is the name of the event to track, with a maximum length of 30 characters. | Mobile, Web |
| properties | Map? | This is additional information about the event. | |||
| updateUser | TraModifies user information. | name | String? | A name of a user. | Mobile, Web |
| String? | An email of a user. | ||||
| mobileNumber | String? | A mobile number of a user. | |||
| avatarUrl | String? | An avatar URL of a user. | |||
| language | Language? | A user’s language. It is valid when creating a new user. The language of the user that already exists will not change. | |||
| unsubscribeEmail | bool? | Sets whether to receive marketing messages via email. | |||
| unsubscribeTexting | bool? | Sets whether to receive marketing messages via texting (SMS, LMS) | |||
| tags | List[String]? | A tag list of the user. | |||
| customAttributes | Map < String, dynamic >? | A user's CustomAttributes | |||
| initPushToken | Informs ChannelTalk about updates to the device token. | deviceToken* | String | This is additional information about the event. | Mobile |
| isChannelPushNotification | It checks if the push data should be processed by the SDK. | content* | Map | This is the `userInfo object received through push notifications. | Mobile |
| receivePushNotification | Notifies Channel Talk that the user has received a push notification. | content* | Map | This is the `userInfo object received through push notifications. | Mobile |
| storePushNotification | Stores push information on the device. | content* | Map | This is the `userInfo object received through push notifications. | Mobile |
| hasStoredPushNotification | Check for any saved push notifications from the Channel. | Mobile | |||
| openStoredPushNotification | Opens a user chat using the stored push information on the device through �storePushNotification. | Mobile | |||
| isBooted | Verify that the SDK is in a Boot state. | Mobile | |||
| setDebugMode | Sets the debug mode. | flag* | String | debug mode | Mobile |
| setPage | Sets the page and user chat profile used by track and new chats. | page, profile | String?, Map<String, dynamic>? | page is the tracked screen name and is required on Web. profile sets user chat profile fields. Both parameters are optional on Android and iOS. | Mobile, Web |
| resetPage | Resets the tracked screen name and user chat profile. | Mobile, Web | |||
| addTags | Adds tags to the user. | tags* | List[String] | • The maximum number of tags that can be added is 10. • Tags are stored in lowercase. • Any tags that have already been added will be ignored. • nil, empty strings, or lists containing them are not allowed. |
Mobile, Web |
| removeTags | Removes tags from the user, ignoring any tags that do not exist. | tags* | List[String] | These are the tags to be removed. Null, empty strings, or lists containing them are not allowed. | Mobile, Web |
| openWorkflow | Opens a user chat and starts the specified workflow. | workflowId | String? | The ID of workflow to start with. An error page will be shown if such workflow does not exist. | Mobile, Web |
| message | String? | This message will be displayed in the input field after completing the support bot operation. | |||
| setAppearance | Configures the SDK's theme. | appearance* | Appearance | If specified as .light or .dark, it locks the theme to the respective mode. If specified as .system, it follows the device's system theme. | Mobile, Web |
| hidePopup | Hides the Channel popup on the global screen. | Mobile, Web | |||
| setPreventDefaultUrlClick | Overrides Channel Talk’s default URL click behavior. When enabled, clicks are passed to the app’s onUrlClicked listener instead of opening in the browser. | prevent* | bool | If true, URL clicks will be delegated to the app's listener through onUrlClicked event instead of opening in the default browser. If false, URLs will open in the default browser as normal. | Mobile, Web |
Contributions are welcome! Feel free to open an issue or submit a pull request if you have a way to improve this project.
Make sure your request is meaningful and you have tested the app locally before submitting a pull request.
💙 If you like this project, give it a ⭐ and share it with friends!