[Background]
이번에 프로젝트를 진행하게 되면서 채팅방 구현이 필요했는데, 막상 일일이 직접 구현을 하자니 너무 막막하고 시간이 오래 걸릴 듯해서 샌드버드를 사용해 채팅을 간단하게 구현하려고 했다.
샌드버드에서 UIKit라는 것을 제공하는데 잘만 사용한다면 진짜 5분만에 채팅을 도입할 수 있지만 샌드버드에 없는 기능을 붙이거나 디자인 변경 심지어 Hilt을 붙이는 것조차 애를 먹었다.
그래서 Customization에 대해서 알아보고 실제로 도입해봤는데 관련 자료가 매우 적고 이 것을 실제로 다룬 사람이 매우 적기에 힘들었던 경험이 있어서 누군가에게 도움이 될 수 있다면 좋을 듯해서 이 글을 작성해 봤습니다.
이 글에 사용된 버전들
- Java 17
- Gradle 8.0.2
- kotlin 1.8.20
- SendBird UIKIt 3.8
[샌드버드 UIKit에 대해서]
먼저 시작하기 앞서서 샌드버드 UIKit은 어떻게 동작하는지 아키텍처로 확인을 해보겠습니다
샌드버드의 UIKit의 경우에는 Android Platform와 SDK 위에 도입되어 있고 서로 간 의존을 합니다.
Chat SDK는 샌드버드 서버와 직접적으로 통신하며 각종 기능들을 UIKit에 제공합니다. (예, 메시지 전송, 읽음 표시)
그리고 UIKit & Application은 SDK를 사용하여 개발자가 쉽게 UI를 도입하게 도와줍니다.
간단히 말하면, 샌드버드의 UIKit은 개발자에게 SDK에 포함된 기능들을 이미 구현된 화면을 제공해 줍니다.
UIKit 내부를 자세히 살펴보면 주로 두 개 부분으로 나눌 수 있습니다. 뷰를 담당하고 있는 부분들과 데이터 + API 부분을 담당하고 있는 부분.
각각 부분이 어떤 역할을 하고 있는지 내부 코드를 이용해 간단하게 보여드리겠습니다. (내부는 Java코드로 중요한 흐름만 보여드리기 때문에 간략화했습니다)
-Activity
public class ChannelActivity extends AppCompatActivity {
// Intent 만들기
public static Intent newIntent(@NonNull Context context) {...}
// 화면 전환하기
public static Intent newRedirectToMessageThreadIntent(@NonNull Context...) {...}
// 커스텀 Activity로 화면 전환하기
public static Intent newIntentFromCustomActivity(@NonNull Context context...) {...}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int themeResId = getIntent().getIntExtra(StringSet.KEY_THEME_RES_ID...);
setContentView(R.layout.sb_activity);
Fragment fragment = createFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction()
.replace(R.id.sb_fragment_container, fragment)
.commit();
}
}
샌드버드에서는 Activity를 거의 활용하지 않습니다.
하는 일은 Activity 위에 Fragment을 뛰우거나, 다른 Activity에 화면 전환하기만 합니다
- Fragment
public class ChannelFragment {
@Override
protected ChannelModule onCreateModule(...) {...}
@Override
protected ChannelViewModel onCreateViewModel(...){...}
protected void onBindChannelHeaderComponent(...) {...}
protected void onBindMessageListComponent(...) {...}
protected void onBindMessageInputComponent(...) {...}
protected void onBindStatusComponent(...){...}
}
Fragment는 샌드버드 UIKit에서 가장 중요한 부분으로 Module이 제공하는 뷰와 뷰 모델이 제공하는 데이터와 API를 결합(Bind) 시키는 역할을 하고 있습니다.
여기서 Module이 제공하는 뷰는 Components으로 예시에서는 ChannelHeaderComponent, MessageListComponent 등등이 있다. 이 Component들이 어떻게 동작할지 설정해 주는 역할을 하고 있다 (예, 메시지를 전송했을 때 어떤 SDK 부분을 사용할지)
- Module
public class ChannelModule {
@Override
public View onCreateView(...) {
final LinearLayout parent = new LinearLayout(context);
parent.setLayoutParams(...);
parent.setOrientation(LinearLayout.VERTICAL);
final FrameLayout bodyContainer = new FrameLayout(context);
bodyContainer.setLayoutParams(...)
parent.addView(bodyContainer);
final View messageListLayout = getMessageListComponent().onCreateView(...);
bodyContainer.addView(messageListLayout);
}
}
Module은 화면에 보여줄 모든 뷰를 제공하는 역할을 하고 있다. 각 Fragment은 한 개의 Module를 가지고 있고 한개의 Module은 여러 개의 Component을 가지고 있다.
예시에서는 Parent이라는 LinearLayout을 만들어서 그 안에 MessageListComponent을 제공했습니다.
- Component
public class MessageListComponent {
@Override
protected void onListItemClicked(...) {...}
@Override
protected void onListItemLongClicked(...) {...}
}
Component은 뷰의 작은 부분들을 만든다.
여기서는 메시지를 클릭했을 때 어떻게 반응하는지 설정하고 있습니다
- Style/Res
각각 Component들을 그리기 위한 Layout이나 Style에 대해서 정의를 하고 있습니다.
[UIKit 도입하기]
이 부분 하기 앞서서 SendBird 계정을 만들고 DashBoard에서 Application ID을 가지고 계셔야 합니다!
그러면 한번 UIKit을 어떻게 사용하는지 알아보겠습니다. 사용하시면 제가 처음에 왜 만드는데 5분밖에 안 걸리는지 알게 되실 겁니다
기본사항
- Android 5.0 (API 21) 이상
- Java 8 이상
- androidx만 지원
- Gradle Plugin 4.0.1 이상
- Chat SDK 4.0.3 이상
1. Setting.gradle
밑에 두 줄을 추가
dependencyResolutionManagement {
repositories {
maven { url "https://jitpack.io" }
maven { url "https://repo.sendbird.com/public/maven" }
}
}
2. build.gradle (Module: app)
dependencies {
implementation 'com.sendbird.sdk:uikit:3.+'
}
이렇게 사용하면 +를 사용하면 안 된다고 warning이 뜰 건데 무시하셔도 무방합니다.
멀티 모듈 프로젝트를 진행 중이면 UIKit를 사용하는 모듈에도 넣어야 한다.
3. Application Class
class SendBirdApplication : Application() {
override fun onCreate() {
super.onCreate()
initSendBirdUI()
initSendBirdChat()
}
private fun initSendBirdChat() {
SendbirdChat.init(
InitParams(
"APPLICATION ID" // 자신의 Application ID 입력해주세요,
applicationContext,
useCaching = true
),
object : InitResultHandler {
override fun onInitFailed(e: SendbirdException) {
// 실패시 예외처리
}
override fun onInitSucceed() {
SendbirdChat.connect("USER_ID") { user, e -> // 채팅을 진행할 사용자 ID 입력
if (user != null) {
if (e != null) {
// User가 없을때 예외처리, 대부분 자동으로 생성됩니다
} else {
}
} else {
// Handle error.
}
}
}
override fun onMigrationStarted() {
}
}
)
}
private fun initSendBirdUI() {
SendbirdUIKit.init(object : SendbirdUIKitAdapter {
override fun getAppId(): String {
return "Application ID" // 자신의 Application ID
}
override fun getAccessToken(): String {
return ""
}
override fun getUserInfo(): UserInfo {
return object : UserInfo {
override fun getUserId(): String {
return "USER_ID" // 채팅을 진행할 사용자 ID 입력
}
override fun getNickname(): String {
return "USER_NAME" // 채팅을 진행할 사용자 닉네임
}
override fun getProfileUrl(): String {
return "" // 사용자 프로필 사진 주소 (SendBird에 사진 저장 가능)
}
}
}
override fun getInitResultHandler(): InitResultHandler {
return object : InitResultHandler {
override fun onInitFailed(e: SendbirdException) {
}
override fun onInitSucceed() {
}
override fun onMigrationStarted() {
}
}
}
}, this)
}
}
SendBird UIKit와 SendBirdChannel에 자신의 SendBird 계정에 있는 Application ID을 입력하고 사용자의 정보를 입력해 주면 연결이 완료됩니다.
5. Manifest에 Application 추가
<application
android:name=".SendBirdApplication" // 이 부분 추가
android:label="@string/app_name"
android:theme="@style/Theme.SendBird_Demo">
<activity
android:exported="true"
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
6. Activity에 sendBird 상속받기
class MainActivity : ChannelListActivity() {
}
이렇게 하고 실행 시 다 잘 입력이 되어있으면 바로 채팅 화면이 나옵니다.
(다른 사용자 추가해서 테스트했습니다 사용자 DashBoard에서 생성 후 오른쪽 상단 버튼 누르면 채팅 시작 가능합니다)
여기까지는 공식 문서에서도 쉽게 확인이 가능한 부분이라 매우 간단하지만, Customization을 시작하는 순간 소스도 거의 없고 공식 문서에서도 겁나 간략하게 명시되어 있어서 하기 힘드실 겁니다.
이번 글에서는 간단하게 ChannelList에 있는 헤드 부분을 수정하는 방법만 살펴보겠습니다
[Customization 맛보기]
앞에서 UIKit을 설명한 순서대로 Custom Class을 만들어서 필요한 부분을 오버라이드해서 변경해 주면 됩니다.
1. Fragment
class CustomChannelList : ChannelListFragment() {
override fun onCreateModule(args: Bundle): ChannelListModule {
val module: ChannelListModule = super.onCreateModule(args)
module.setHeaderComponent(CustomHeader())
return module
}
}
Module 안에 있는 Component을 바꾸는 작업이기 때문에 Module을 받아서 그 안에 있는 Header 부분을 변경해 주면 됩니다. Module의 역할은 Component을 제공해 주는 것인데, Fragment에서 처리가 가능해서 따로 해줄게 없습니다.
2. Component
class CustomHeader : HeaderComponent() {
override fun onCreateView(
context: Context,
inflater: LayoutInflater,
parent: ViewGroup,
args: Bundle?
): View {
val view = inflater.inflate(R.layout.custom_header, parent, false)
return view
}
}
다음은 Component, onCreateView을 오버라이드해서 만든 커스텀 헤더를 넣어줍니다.
3. UIFactory
현재는 저희가 Fragment을 만들었을 뿐 SendBird UIKit한테 뭐를 만들었는지 안 알려줬습니다. 이 역할은 UIKItFragmentFactory가 합니다.
class CustomFactory : UIKitFragmentFactory() {
override fun newChannelListFragment(args: Bundle): Fragment {
val fragment = CustomChannelList()
fragment.arguments = args
return fragment
}
}
UIKitFragmentFactory를 상속받아서 저희가 만든 커스텀 ChannelListFragment을 넘겨줍니다.
그리고 처음 SendBirdUI를 시작하는 Application class에 이 커스텀 Factory를 넘겨줍니다
private fun initSendBirdUI() {
SendbirdUIKit.init(object : SendbirdUIKitAdapter {...}
SendbirdUIKit.setUIKitFragmentFactory(CustomFactory())
}
이제 실행해 보면 성공적으로 바뀐 걸 볼 수 있다!
[마무리]
이번 글에서는 어떻게 UIKit이 구성돼있고 간단하게 Customization 하는 방법에 대해서 알아봤습니다.
Fragment안에는 어떤 Module, Component이 있을지 정말로 감도 안 잡히실 건데
여기를 참고하시면 됩니다
https://sendbird.com/docs/chat/uikit/v3/android/modules/overview
그 외에도 채팅방 메시지 검색, 채팅방 만들기, 커스텀 채팅방 리스트 등등 아직 다루지 못한 게 많지만 분량상 다음 글로 넘기겠습니다
시간이 있을 때 CustomChannelList를 어떻게 만드는지에 대해서 다뤄 보겠습니다
전체 코드는 여기서 참고 가능합니다
https://github.com/flash159483/sendbird_customization
GitHub - flash159483/sendbird_customization
Contribute to flash159483/sendbird_customization development by creating an account on GitHub.
github.com
P.S 처음 써본 블로그 글이라 어색하네요
'android > SendBird' 카테고리의 다른 글
(android/kotlin) 샌드버드 채팅(Channel) 커스텀 해보기 + 3.9 버전 변경 사항 (0) | 2023.09.28 |
---|---|
(android/kotlin) 샌드버드 채팅 리스트 (ChannelList) 커스텀 해보기 (0) | 2023.08.26 |