Flutter를 한지 반년 이상 지났지만, 바쁘기도 했고 보통 pub.dev에서 갖다썼기 때문에
마땅히 포스팅할게 없어서 이제서야 관련 글을 작성합니다.
최근, 카카오톡 채널 추가하기 기능을 추가해달라는 요청을 받았는데 찾아보니 pub.dev에도 없고..
네이티브 소스를 좀 작성해야 가능한 것처럼 보여서 코틀린과 Swift로 작업을 진행했습니다.
카카오 개발 설정은 다른 블로그 글도 많기 때문에 생략했습니다.
설정하셔서 해시키도 등록해두시고 native app key를 얻으셔서 진행하시길 바랍니다.
그리고 제가 이해하기로는 카카오톡 친구를 강제적으로 추가해주는 API는 존재하지 않아보이고,
(가입시 카카오에서 제공하는 체크박스 제외)
카카오톡 친구를 보여주어 채널을 추가를 유도하는 정도의 기능만 구현할 수 있어보여서 그렇게 진행하였습니다.
(22. 9. 1) 1년이 지난 지금, 찾아보니 Kakao에서 Flutter를 지원해서 아래 링크를 따라하시면 간단히 할 수 있게 되었네요.
아마 kakao_flutter_sdk 버전 1.0.0이 공식 출시 되면서 22년 3월 경에 해당 링크와 기능을 지원하기 시작한거 같습니다.
낮은 확률로 다른 패키지와 충돌해서 kakao_flutter_sdk를 사용하실 수 없을 수도 있으니
제가 작성한 소스도 남겨 놓도록 하겠습니다.
가능하시면 아래 링크를 통해 연결해보세요.
https://developers.kakao.com/docs/latest/ko/kakaotalk-channel/flutter
1. yaml을 작성한다.
flutter_kakao_login: 3.3.0
url_launcher: 6.0.3 # 카카오톡 설치 여부를 위해 추가
2. main.dart를 작성한다.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_kakao_login/flutter_kakao_login.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '카카오톡 채널 추가 Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: '카카오톡 채널 추가 Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void goKakaoChannel() async {
final installed = await canLaunch(Platform.isIOS ? "kakaokompassauth://authorize" : "kakaolink://");
if (installed) {
final FlutterKakaoLogin kakaoSignIn = new FlutterKakaoLogin();
await kakaoSignIn.init("your_native_app_key");
const MethodChannel _channel = const MethodChannel('myChannel');
_channel.invokeMethod('addKakaoChannel', "your_channel_public_id");
} else {
//카카오톡이 설치되지 않았을때 처리
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
onPressed: goKakaoChannel,
tooltip: '카카오톡 채널 추가',
child: Icon(Icons.add),
)
],
),
),
);
}
}
3. build.gradle(Project)에서 카카오 레파지토리 설정한다.
allprojects {
repositories {
google()
jcenter()
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
}
}
4. build.gradle(Module)에 디펜던시를 설정한다.
dependencies {
implementation "com.kakao.sdk:v2-talk:2.4.2" // 친구, 메시지(카카오톡)
}
5. MainActivity.kt를 작성한다.
package com.risha.blog
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import com.kakao.sdk.talk.*
import com.kakao.sdk.common.util.*
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
val channel = MethodChannel(flutterEngine.getDartExecutor(), "myChannel")
channel.setMethodCallHandler(handler)
}
private val handler: MethodChannel.MethodCallHandler = MethodChannel.MethodCallHandler({ methodCall, result ->
if (methodCall.method.equals("addKakaoChannel")) {
val channelPublicId = methodCall.arguments as String
val url = TalkApiClient.instance.channelChatUrl(channelPublicId)
// CustomTabs 로 열기
KakaoCustomTabsClient.openWithDefault(context, url)
} else {
result.notImplemented()
}
})
}
6. Podfile을 작성한다.
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
pod 'KakaoSDKTalk' # 친구, 메시지(카카오톡)
작성 뒤, pod install합니다.
7. Info.plist를 작성한다.
<key>LSApplicationQueriesSchemes</key>
<array>
<!-- common -->
<string>kakao${your_native_app_key}</string>
<!-- KakaoTalk login -->
<string>kakaokompassauth</string>
<string>storykompassauth</string>
</array>
8. AppDelegate.swift를 작성한다.
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var navigationController: UINavigationController!
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
linkNativeCode(controller: controller)
GeneratedPluginRegistrant.register(with: self)
self.navigationController = UINavigationController(rootViewController: controller)
self.window.rootViewController = self.navigationController
self.navigationController.setNavigationBarHidden(true, animated: false)
self.window.makeKeyAndVisible()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func addKakaoChannel(call: FlutterMethodCall, result: @escaping FlutterResult) {
let vc = UIStoryboard.init(name: "Main", bundle: .main)
.instantiateViewController(withIdentifier: "ViewController") as! ViewController
if let arguments = call.arguments as? String {
vc.arguments = arguments
}
vc.result = result
self.navigationController.pushViewController(vc, animated: true)
}
}
extension AppDelegate {
func linkNativeCode(controller: FlutterViewController) {
setupMethodChannel(controller: controller)
}
private func setupMethodChannel(controller: FlutterViewController) {
let commonChannel = FlutterMethodChannel(name: "myChannel",
binaryMessenger: controller.binaryMessenger)
commonChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
// Note: this method is invoked on the UI thread.
//let viewController = ViewController()
if call.method == "addKakaoChannel" {
self.addKakaoChannel(call: call, result: result)
}
})
}
}
9. ViewController.swift를 작성한다.
import UIKit
import SafariServices
import KakaoSDKTalk
class ViewController: UIViewController, SFSafariViewControllerDelegate {
var result: FlutterResult!
var arguments: String!
var safariViewController : SFSafariViewController? // to keep instance
override func viewDidLoad() {
super.viewDidLoad()
self.safariViewController = SFSafariViewController(url: TalkApi.shared.makeUrlForChannelChat(channelPublicId: arguments)!)
guard (self.safariViewController != nil) else { return }
self.safariViewController?.modalTransitionStyle = .crossDissolve
self.safariViewController?.modalPresentationStyle = .overCurrentContext
self.safariViewController?.delegate = self
self.present(self.safariViewController!, animated: true) {
print("Kakao Talk Channel chat 연결 페이지 실행 성공")
}
}
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
//To access the Specific tabBar ViewController
self.navigationController?.popViewController(animated: true)
}
}
10. Storyboard ID를 작성한다.
AppDelegate.swift의 instantiateViewController(withIdentifier: "ViewController")는
Main.storyboard에 ViewController를 추가하신 뒤, Storyboard ID를 withIdentifier 값으로 기입하시면 됩니다.
참고 출처 :
https://blog.usejournal.com/integrating-native-third-party-sdk-in-flutter-8aab03afa9da
https://developers.kakao.com/docs/latest/ko/kakaotalk-channel/ios