
์ธ์ด ๐ฐ๐ท ํ๊ตญ์ด
๋ฌธ์
์์ํ๊ธฐ
์ฌ์ฉ๋ฒ
์ธ์ฆ
๊ตฌ์ฑ
FastComments Android Library
์ด๊ฒ์ FastComments์ ๊ณต์ Android ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
Android์ฉ FastComments ๋๊ธ ์์ ฏ
์ ์ฅ์
๊ธฐ๋ฅ 
- ๐ ์ค์๊ฐ ์ ๋ฐ์ดํธ๋ฅผ ํตํ ๋ผ์ด๋ธ ๋๊ธ
- ๐ฑ ๋ค์ดํฐ๋ธ Android UI ๊ตฌ์ฑ ์์
- ๐งต ๋ต๊ธ์ ํฌํจํ ์ค๋ ๋ํ ํ ๋ก
- ๐ค ๋ณด์ SSO ์ธ์ฆ
- ๐ ์ฌ์ฉ์ ์ง์ ๊ฐ๋ฅํ ์คํ์ผ์ ํฌํ ์์คํ
- ๐ ์ฌ์ฉ์ ์๋ฆผ ๋ฐ ์ ์ ์ํ
- ๐ ๋๊ธ ์ค์ฌ ๊ธฐ๋ฅ
- ๐ฑ ์์ ํผ๋ ํตํฉ
- โพ๏ธ ๋ฌดํ ์คํฌ๋กค ํ์ด์ง ๋งค๊น
- ๐จ ํฌ๊ด์ ์ธ ํ ๋ง
์ค์น 
์ฑ์ build.gradle.kts ํ์ผ์ FastComments SDK๋ฅผ ์ถ๊ฐํ์ธ์:
dependencies {
implementation("com.fastcomments:sdk:0.0.1")
}
ํ๋ก์ ํธ์ settings.gradle.kts ํ์ผ์ Repsy ๋ฆฌํฌ์งํ ๋ฆฌ๊ฐ ํฌํจ๋์ด ์๋์ง ํ์ธํ์ธ์:
dependencyResolutionManagement {
repositories {
maven {
url = uri("https://repo.repsy.io/mvn/winrid/fastcomments")
}
// ๋ค๋ฅธ ๋ฆฌํฌ์งํ ๋ฆฌ...
}
}
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ 
1. ๋ ์ด์์์ FastCommentsView ์ถ๊ฐ
<com.fastcomments.sdk.FastCommentsView
android:id="@+id/commentsView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
2. SDK ์ด๊ธฐํ ๋ฐ ๊ตฌ์ฑ
// SDK ๊ตฌ์ฑ
val config = CommentWidgetConfig(
"your-tenant-id",
"page-url-id",
"Page Title",
"yourdomain.com",
"Site Name"
)
// ์ถ๊ฐ ๊ตฌ์ฑ ์ต์
config.voteStyle = VoteStyle.UpDown // ๋๋ VoteStyle.Heart
config.enableInfiniteScrolling = true
config.hasDarkBackground = true // ๋คํฌ ๋ชจ๋ ์ง์์ฉ
// SDK ์ด๊ธฐํ
val sdk = FastCommentsSDK(config)
// ๋ ์ด์์์์ ๋๊ธ ๋ทฐ ์ฐพ๊ธฐ
val commentsView = findViewById<FastCommentsView>(R.id.commentsView)
// ๋ทฐ์ SDK ์ธ์คํด์ค ์ค์
commentsView.setSDK(sdk)
// ๋๊ธ ๋ก๋
commentsView.load()
๋ณด์ SSO ์ธ์ฆ 
์ฌ์ฉ์์ ๋ํ ๋ณด์ ์ธ์ฆ์ ๊ตฌํํ์ธ์:
// ์ฌ์ฉ์ ๋ฐ์ดํฐ ์์ฑ(๊ถ์ฅ: ์๋ฒ ์ธก์์)
val userData = SecureSSOUserData(
"user-id",
"user@example.com",
"User Name",
"https://path-to-avatar.jpg"
)
// SSO ํ ํฐ ์์ฑ(์๋ฒ์์ ์ํํด์ผ ํฉ๋๋ค!)
val sso = FastCommentsSSO.createSecure("YOUR_API_KEY", userData)
val token = sso.prepareToSend()
// ๊ตฌ์ฑ์ ์ถ๊ฐ
config.sso = token
ํผ๋ ์ฐ๋ 
๋๊ธ์ด ํฌํจ๋ ์์ ๋ฏธ๋์ด ์คํ์ผ ํผ๋ ํ์:
// SDK ๊ตฌ์ฑ
CommentWidgetConfig config = new CommentWidgetConfig();
config.tenantId = "your-tenant-id";
config.urlId = "page-url-id";
// ํผ๋ SDK ์ด๊ธฐํ
FastCommentsFeedSDK feedSDK = new FastCommentsFeedSDK(config);
// ํผ๋ ๋ทฐ ์ค์
FastCommentsFeedView feedView = findViewById(R.id.feedView);
feedView.setSDK(feedSDK);
// ์ํธ์์ฉ ๋ฆฌ์ค๋ ์ค์
feedView.setFeedViewInteractionListener(new FastCommentsFeedView.OnFeedViewInteractionListener() {
@Override
public void onFeedLoaded(List<FeedPost> posts) {
// ํผ๋ ๋ก๋ ์ฑ๊ณต
}
@Override
public void onFeedError(String errorMessage) {
// ์ค๋ฅ ์ฒ๋ฆฌ
}
@Override
public void onPostSelected(FeedPost post) {
// ์ฌ์ฉ์๊ฐ ๊ฒ์๋ฌผ์ ์ ํํจ
}
@Override
public void onCommentsRequested(FeedPost post) {
// ๊ฒ์๋ฌผ์ ๋๊ธ ํ์
CommentsDialog dialog = new CommentsDialog(context, post, feedSDK);
dialog.show();
}
});
// Load the feed
feedView.load();
๋ผ์ด๋ธ ์ฑํ
์ฐ๋ 
์ฑ์ ์ค์๊ฐ ์ฑํ ์ธํฐํ์ด์ค๋ฅผ ์ถ๊ฐํ์ธ์:
// ๋ ์ด์์ XML์ LiveChatView ์ถ๊ฐ
// <com.fastcomments.sdk.LiveChatView
// android:id="@+id/liveChatView"
// android:layout_width="match_parent"
// android:layout_height="match_parent" />
// Create a configuration for the SDK
val config = CommentWidgetConfig().apply {
tenantId = "your-tenant-id"
urlId = "chat-room-identifier"
pageTitle = "Chat Room Name"
}
LiveChatView.setupLiveChatConfig(config)
// ์ ํ ์ฌํญ: ์ฌ์ฉ์ ์ธ์ฆ ์ถ๊ฐ
val userData = SimpleSSOUserData(
"User Name",
"user@example.com",
"https://path-to-avatar.jpg"
)
val sso = FastCommentsSSO(userData)
config.sso = sso.prepareToSend()
// SDK ์ด๊ธฐํ
val sdk = FastCommentsSDK().configure(config)
// ๋ผ์ด๋ธ ์ฑํ
๋ทฐ ์ค์
val liveChatView = findViewById<LiveChatView>(R.id.liveChatView)
liveChatView.setSDK(sdk)
liveChatView.load()
// ๋ผ์ดํ์ฌ์ดํด ์ฒ๋ฆฌ๋ฅผ ์์ง ๋ง์ธ์
override fun onResume() {
super.onResume()
sdk.refreshLiveEvents()
}
override fun onDestroy() {
super.onDestroy()
sdk.cleanup()
}
์์ ํ๋ก์ ํธ 
๋ค์ ๋ฐ๋ชจ ๊ตฌํ์ ํ์ธํด๋ณด์ธ์:
- ๊ธฐ๋ณธ ๋๊ธ ์์
- ๋ณด์ SSO ๊ตฌํ ์์
- ํผ๋ ํตํฉ ์์
- ๋ผ์ด๋ธ ์ฑํ ์์
- ๋๊ธ ๋ํ์์ ์์
๊ตฌ์ฑ ์ต์

์ด SDK๋ CommentWidgetConfig ํด๋์ค์์ ๋ค์ํ ๊ตฌ์ฑ ์ต์
์ ์ ๊ณตํฉ๋๋ค:
| Option | Description |
|---|---|
tenantId |
FastComments ๊ณ์ ID |
urlId |
ํ์ฌ ํ์ด์ง๋ฅผ ๋ํ๋ด๋ ID |
sso |
์ธ์ฆ์ ์ํ SSO ํ ํฐ |
allowAnon |
์ต๋ช ๋๊ธ ํ์ฉ |
voteStyle |
UpDown ๋๋ Heart ํฌํ ์คํ์ผ |
hideAvatars |
์ฌ์ฉ์ ์๋ฐํ ์จ๊ธฐ๊ธฐ |
hasDarkBackground |
๋คํฌ ๋ชจ๋ ์ฌ๋ถ |
customCSS |
์ฌ์ฉ์ ์ ์ CSS ์คํ์ผ |
enableInfiniteScrolling |
๋ฌดํ ์คํฌ๋กค ํ์ด์ง ํ์ฑํ |
readonly |
๋๊ธ ์์ฑ ๋นํ์ฑํ(๋๊ธ ํ์) |
disableVoting |
ํฌํ ๊ธฐ๋ฅ ๋นํ์ฑํ |
disableLiveCommenting |
์ค์๊ฐ ์ ๋ฐ์ดํธ ๋นํ์ฑํ |
ํฌ๊ด์ ์ธ ํ
๋ง ๋ง์ถคํ 
FastComments SDK์ ๋ชจ๋ ๋ฒํผ ๋ฐ UI ์์๋ ํ
๋ง ์ค์ ์ด ๊ฐ๋ฅํฉ๋๋ค. ์ฑ ๋ธ๋๋ฉ์ ์์ ํ ์ ์ดํ๋ ค๋ฉด FastCommentsTheme.Builder๋ฅผ ์ฌ์ฉํ์ธ์.
ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์ ํ ๋ง ์ ์ฉ (๊ถ์ฅ)
val theme = FastCommentsTheme.Builder()
// ์์
๋ฒํผ: ์ ์ก, ํฌํ, ๋ฉ๋ด, ์ข์์/๊ณต์ ๋ฒํผ
.setActionButtonColor(Color.parseColor("#FF1976D2"))
// ๋ต๊ธ ๋ฒํผ: ๋๊ธ ๋ต๊ธ ๋ฒํผ
.setReplyButtonColor(Color.parseColor("#FF4CAF50"))
// ํ ๊ธ ๋ฒํผ: ๋ต๊ธ ํ์/์จ๊ธฐ๊ธฐ ๋ฒํผ
.setToggleRepliesButtonColor(Color.parseColor("#FFFF5722"))
// ๋ ๋ณด๊ธฐ ๋ฒํผ: ํ์ด์ง ๋งค๊น ๋ฒํผ
.setLoadMoreButtonTextColor(Color.parseColor("#FF9C27B0"))
.setPrimaryColor(Color.parseColor("#FF6200EE"))
.setLinkColor(Color.parseColor("#FF1976D2"))
.setDialogHeaderBackgroundColor(Color.parseColor("#FF333333"))
.build()
// ํ
๋ง ์ ์ฉ
sdk.setTheme(theme)
๋น ๋ฅธ ์์ ์ฌ์ ์
๊ฐ๋จํ ๋ธ๋๋ฉ์ ์ํด colors.xml์ ์์ ๋ฆฌ์์ค๋ฅผ ์ค๋ฒ๋ผ์ด๋ํ์ธ์:
<!-- ์ฑ์ res/values/colors.xml์์ -->
<resources>
<!-- ๋ชจ๋ ์ฃผ์ UI ์์ ๋ณ๊ฒฝ -->
<color name="primary">#FF1976D2</color>
<!-- ๋๋ ํน์ ๋ฒํผ ์ ํ์ ์ฌ์ฉ์ํ -->
<color name="fastcomments_action_button_color">#FF1976D2</color>
<color name="fastcomments_reply_button_color">#FF4CAF50</color>
<color name="fastcomments_toggle_replies_button_color">#FFFF5722</color>
<color name="fastcomments_load_more_button_text_color">#FF9C27B0</color>
</resources>
ํ ๋ง ์ ์ฉ ๋ฒํผ ๋ฒ์
SDK์ ๋ชจ๋ ๋ฒํผ์ ํ ๋ง๋ฅผ ์ง์ํฉ๋๋ค:
- ์ ์ก ๋ฒํผ, ํฌํ ๋ฒํผ, ๋ฉ๋ด ๋ฒํผ, ๋ต๊ธ ๋ฒํผ
- ๋ต๊ธ ํ์/์จ๊ธฐ๊ธฐ ๋ฒํผ, ๋ ๋ณด๊ธฐ ๋ฒํผ
- ํผ๋ ์ก์ ๋ฒํผ(์ข์์, ๋๊ธ, ๊ณต์ )
- ๋ค์ด์ผ๋ก๊ทธ ๋ฒํผ(์ ์ถ, ์ทจ์, ์ ์ฅ)
- ํผ๋ ๊ฒ์๋ฌผ์ ๋์ ์์ ๋ฒํผ
์์ธํ ํ ๋ง ๋ฌธ์๋ THEMING.md๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ 
๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง
Activity ๋๋ Fragment์์ FastComments ๋ทฐ๋ฅผ ์ฌ์ฉํ ๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด, ๋ ์ด์ ๋ทฐ๊ฐ ํ์ํ์ง ์์ ๋ ํญ์ cleanup()์ ํธ์ถํ์ธ์:
์กํฐ๋นํฐ์์:
@Override
protected void onDestroy() {
super.onDestroy();
// ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด FastComments ๋ทฐ๋ฅผ ์ ๋ฆฌํฉ๋๋ค
if (feedView != null) {
feedView.cleanup();
}
if (commentsView != null) {
commentsView.cleanup();
}
}
ํ๋๊ทธ๋จผํธ์์:
@Override
public void onDestroyView() {
super.onDestroyView();
// ํ๋๊ทธ๋จผํธ ๋ทฐ๊ฐ ํ๊ดด๋ ๋ FastComments ๋ทฐ๋ฅผ ์ ๋ฆฌํฉ๋๋ค
if (feedView != null) {
feedView.cleanup();
feedView = null;
}
}
@Override
public void onDestroy() {
super.onDestroy();
// ํ๋๊ทธ๋จผํธ๊ฐ ํ๊ดด๋ ๋ ์ถ๊ฐ ์ ๋ฆฌ ์ํ
if (feedSDK != null) {
feedSDK.cleanup();
feedSDK = null;
}
}
ํ๋๊ทธ๋จผํธ๋ฅผ ์ ํํ ๋:
// FastComments ๋ทฐ๋ฅผ ํฌํจํ ํ๋๊ทธ๋จผํธ๋ฅผ ๊ต์ฒด ๋๋ ์ ๊ฑฐํ๊ธฐ ์ ์
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
if (currentFragment instanceof YourFragmentWithFeedView) {
((YourFragmentWithFeedView) currentFragment).cleanupFeedView();
}
// Then proceed with fragment transaction
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, newFragment)
.commit();
์ค์: ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด ํญ์ cleanup() ๋ฉ์๋๋ฅผ ํธ์ถํ์ธ์. ํนํ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ:
- ์กํฐ๋นํฐ๊ฐ ์ข ๋ฃ๋ ๋
- ํ๋๊ทธ๋จผํธ ๋ทฐ๊ฐ ํ๊ดด๋ ๋
- ํ๋๊ทธ๋จผํธ ๊ฐ ์ ํ ์
- FastComments ์ปดํฌ๋ํธ๋ฅผ ํฌํจํ ํ๋ฉด์์ ์ด๋ํ ๋
๋์์ ์ํ์๋์?
Android ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ด๋ จํ์ฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฑฐ๋ ์ง๋ฌธ์ด ์๋ ๊ฒฝ์ฐ, ๋ค์์ ์ด์ฉํ์ธ์:
๊ธฐ์ฌ
๊ธฐ์ฌ๋ ํ์ํฉ๋๋ค! ๊ธฐ์ฌ ์ง์นจ์ GitHub ์ ์ฅ์์์ ํ์ธํ์ธ์.