
言語 🇯🇵 日本語
ドキュメント
はじめに
認証
使用方法
iOSアプリにコメントを追加する
これは FastComments の公式 iOS ライブラリです。
iOS アプリにライブコメント、チャット、レビューのウィジェットを埋め込むことができます。
リポジトリ
機能 
- ネストされた返信とページネーションを備えたスレッド形式のコメントツリー
- 投稿作成、リアクション、メディア添付を備えたソーシャルフィード
- 自動スクロールと日付区切りを備えたライブチャットモード
- WebSocket を介したリアルタイム更新(新しいコメント、投票、プレゼンス)
- シングルサインオン(テスト用の簡易 SSO、運用向けのセキュア SSO)
- 太字、斜体、コード、@メンションを含むリッチテキスト編集
- 設定可能なスタイル(上/下の矢印またはハート)を持つ投票機能
- モデレーション操作:フラグ、ピン、ロック、ブロック
- プリセットとフルカスタマイズを備えた包括的なテーマ
- コメントとフィード投稿作成のためのカスタムツールバーボタン
- 画像アップロード
- EUリージョンのサポート
- ユーザーのプレゼンス(オンライン/オフライン表示)
- タグベースのフィードフィルタリング
- ローカリゼーションのサポート
インストール 
Swift Package Managerを使用してFastCommentsUIをプロジェクトに追加します。
Xcodeで: File > Add Package Dependencies を選択し、リポジトリのURLを入力します。
または、Package.swift に追加します:
dependencies: [
.package(url: "https://github.com/fastcomments/fastcomments-ios.git", from: "1.0.0")
]
次に、ターゲットに製品を追加します:
.target(
name: "YourApp",
dependencies: [
.product(name: "FastCommentsUI", package: "fastcomments-ios")
]
)
必要な箇所で両方のモジュールをインポートします:
import FastCommentsUI
import FastCommentsSwift
クイックスタート 
コメントウィジェットを表示するための最小限のセットアップ:
import SwiftUI
import FastCommentsUI
struct ContentView: View {
@StateObject private var sdk = FastCommentsSDK(
config: FastCommentsWidgetConfig(
tenantId: "demo",
urlId: "my-page-1",
url: "https://example.com/page-1",
pageTitle: "My Page"
)
)
var body: some View {
FastCommentsView(sdk: sdk)
.task {
try? await sdk.load()
}
}
}
"demo" をあなたの FastComments テナント ID に置き換えてください。urlId はコメントが保存されるページまたはスレッドを識別します。
認証(SSO) 
FastComments は 3 つの認証モードをサポートしています:
- Anonymous -- SSO トークンなし; ユーザーはセッションベースの識別を取得します
- Simple SSO -- デモやテスト用のクライアント側トークン(安全ではありません)
- Secure SSO -- 本番向けのサーバー署名トークン
Simple SSO
デモやローカルテストに便利です。Simple SSO では誰でも任意のユーザーをなりすますことができるため、本番環境では使用しないでください。
import FastCommentsSwift
let userData = SimpleSSOUserData(
username: "Jane Doe",
email: "jane@example.com",
avatar: "https://example.com/avatar.jpg"
)
let sso = FastCommentsSSO.createSimple(simpleSSOUserData: userData)
let token = try? sso.prepareToSend()
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-page-1",
sso: token
)
let sdk = FastCommentsSDK(config: config)
SimpleSSOUserData は次のオプションフィールドもサポートします:
id-- ユーザー ID(未設定の場合は email がデフォルト)displayName-- 個別の表示名displayLabel-- 名前の横に表示されるカスタムラベル(例: "VIP")websiteUrl-- ユーザー名に付くリンクlocale-- ロケールコードisProfileActivityPrivate-- プロファイルアクティビティを非表示にする(デフォルトは true)
Secure SSO
本番環境では、バックエンドが API シークレットを使って署名付き SSO トークンを生成します。iOS アプリはサーバーからこのトークンを取得し、config に渡します。
バックエンド側(FastComments Swift SDK または任意の言語を使用):
let userData = SecureSSOUserData(
id: "user-123",
email: "user@example.com",
username: "Display Name",
avatar: "https://example.com/avatar.jpg"
)
let sso = try FastCommentsSSO.createSecure(apiKey: "YOUR_API_KEY", secureSSOUserData: userData)
let token = try sso.prepareToSend()
// このトークンを API 経由で iOS アプリに返します
iOS アプリ内で:
struct MyView: View {
@StateObject private var sdk = FastCommentsSDK(
config: FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-page-1"
)
)
@State private var isLoadingToken = true
var body: some View {
Group {
if isLoadingToken {
ProgressView("Loading...")
} else {
FastCommentsView(sdk: sdk)
}
}
.task {
// バックエンドからトークンを取得
let token = try? await fetchSSOTokenFromYourBackend()
// トークンで新しい config を作成するか、ロード前に設定する
isLoadingToken = false
try? await sdk.load()
}
}
}
SecureSSOUserData は追加のフィールドをサポートします:
optedInNotifications-- メール通知のオプトインdisplayLabel-- カスタムラベルdisplayName-- 表示名websiteUrl-- ウェブサイトの URLgroupIds-- グループ所属isAdmin-- 管理者権限isModerator-- モデレーター権限isProfileActivityPrivate-- プロフィールの非公開設定
スレッドコメント 
基本的な使用法
struct CommentsPage: View {
@StateObject private var sdk = FastCommentsSDK(
config: FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "article-42",
url: "https://example.com/article/42",
pageTitle: "Article Title"
)
)
var body: some View {
FastCommentsView(sdk: sdk)
.task {
try? await sdk.load()
}
}
}
投票スタイル
デフォルトの投票スタイルは上下の矢印を表示します。ハート型の投票にするには ._1 を渡します:
FastCommentsView(sdk: sdk, voteStyle: ._1)| Style | 外観 |
|---|---|
._0 | Up/down arrow buttons with net count |
._1 | Single heart button with count |
イベントコールバック
モディファイア形式のコールバックを使ってユーザー操作を処理します:
FastCommentsView(sdk: sdk)
.onCommentPosted { comment in
print("New comment: \(comment.commentHTML)")
}
.onReplyClick { renderableComment in
print("Replying to: \(renderableComment.comment.id)")
}
.onUserClick { context, userInfo, source in
// source は .name または .avatar です
print("Tapped \(userInfo.displayName)")
}
テーマの適用
SwiftUI の環境を通じてテーマを渡します:
FastCommentsView(sdk: sdk)
.fastCommentsTheme(myTheme)
.task { try? await sdk.load() }
または SDK に直接設定します:
sdk.theme = FastCommentsTheme.modern
ソート方向
sdk.defaultSortDirection = .nf // 新しい順(デフォルト)
sdk.defaultSortDirection = .of // 古い順
sdk.defaultSortDirection = .mr // 最も関連性の高い
ライブチャット 
LiveChatViewは自動スクロール、日付区切り、コンパクトなレイアウトを備えたリアルタイムチャット体験を提供します。SDKを古い順(oldest-first)のソートと即時ライブ表示用に自動的に構成します。
struct ChatView: View {
@StateObject private var sdk: FastCommentsSDK = {
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "chat-room-1",
sso: ssoToken // ユーザーに名前が表示されるよう、SSOの使用を推奨します
)
return FastCommentsSDK(config: config)
}()
var body: some View {
LiveChatView(sdk: sdk)
.onCommentPosted { comment in
print("Sent: \(comment.commentHTML)")
}
.task {
try? await sdk.load()
}
}
}
LiveChatViewは次のコールバックをサポートします:
.onCommentPosted-- ユーザーがメッセージを送信したときに呼び出されます.onCommentDeleted-- メッセージが削除されたときに呼び出されます.onUserClick-- ユーザーの名前やアバターがタップされたときに呼び出されます
ソーシャルフィード 
フィードシステムは独立した SDK (FastCommentsFeedSDK) で、専用のビューを持ちます。
フィードの読み込みと表示
struct FeedPage: View {
@StateObject private var sdk: FastCommentsFeedSDK = {
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-feed",
sso: ssoToken
)
return FastCommentsFeedSDK(config: config)
}()
@State private var commentsPost: FeedPost?
var body: some View {
FastCommentsFeedView(sdk: sdk)
.onPostSelected { post in
commentsPost = post
}
.onCommentsRequested { post in
commentsPost = post
}
.onSharePost { post in
// 共有シートを表示する
}
.onUserClick { context, userInfo, source in
// ユーザープロファイルへ遷移する
}
.onMediaClick { mediaItem, index in
// フルスクリーンの画像ビューアを表示する
}
.task {
try? await sdk.loadIfNeeded()
}
}
}
フィードビューにはプル・トゥ・リフレッシュと無限スクロールが自動的に含まれます。
画面のライフサイクルに戻る場合は loadIfNeeded() を使用してください。既存または復元されたフィードがページ1にリセットされるのを防ぎます。
投稿の作成
投稿作成フォームを表示するには FeedPostCreateView を使用します:
@State private var showCreatePost = false
// In your view body:
.sheet(isPresented: $showCreatePost) {
FeedPostCreateView(
sdk: sdk,
onPostCreated: { post in
showCreatePost = false
Task { try? await sdk.refresh() }
},
onCancelled: {
showCreatePost = false
}
)
}
投稿へのリアクション
SDKは楽観的更新でリアクションを処理します:
try await sdk.reactPost(postId: post.id, reactionType: "l")
// Check reaction state
let hasLiked = sdk.hasUserReacted(postId: post.id, reactType: "l")
let likeCount = sdk.getLikeCount(postId: post.id)
投稿のコメントを開く
フィード投稿のコメントを表示するには CommentsSheet を使用します。これはフィードSDKの設定を使用して内部で FastCommentsSDK インスタンスを作成します:
.sheet(item: $commentsPost) { post in
CommentsSheet(post: post, feedSDK: sdk, onUserClick: { context, userInfo, source in
// ユーザークリックを処理する
})
}
注意: .sheet(item:) には FeedPost が Identifiable に準拠している必要があります。この拡張を追加してください:
extension FeedPost: @retroactive Identifiable {}
タグベースのフィードフィルタリング
タグでフィード投稿をフィルタリングするには TagSupplier プロトコルを実装します:
struct TeamTagSupplier: TagSupplier {
func getTags(currentUser: UserSessionInfo?) -> [String]? {
guard let user = currentUser else { return nil }
return ["team:\(user.id ?? "")", "public"]
}
}
sdk.tagSupplier = TeamTagSupplier()
フィルタリングされていないグローバルフィードの場合は nil を返してください。
フィード状態の保存と復元
ビューのライフサイクルイベント間でページネーション状態を保持します:
let state = sdk.savePaginationState()
// Later...
sdk.restorePaginationState(state)
try? await sdk.loadIfNeeded()
画面が一時的に非表示になる場合、フィードビューはライブ更新を自動的に一時停止し、再表示時に読み込んだ投稿をクリアせずに再開します。SDKインスタンスを本当に使い終わったときだけ sdk.cleanup() を呼び出してください。
投稿の削除
sdk.onPostDeleted = { postId in
print("Post \(postId) was deleted")
}
テーマ 
テーマプリセット
4つの組み込みプリセットが利用可能です:
// システムのデフォルト
sdk.theme = FastCommentsTheme.default
// 影付きのカード、大きな角丸
sdk.theme = FastCommentsTheme.modern
// フラット、影なし、小さな角丸、スレッド線なし
sdk.theme = FastCommentsTheme.minimal
// すべてのアクションカラーを単一のブランドカラーに設定
sdk.theme = FastCommentsTheme.allPrimary(.indigo)
コメント表示スタイル
var theme = FastCommentsTheme()
theme.commentStyle = .flat // 仕切り付きのフラットリスト(デフォルト)
theme.commentStyle = .card // 影付きの角丸カード
theme.commentStyle = .bubble // チャットバブルスタイル
カラー
すべてのカラー属性は任意です。未設定の値は適切なシステムのデフォルトにフォールバックします。
var theme = FastCommentsTheme()
// ブランドカラー
theme.primaryColor = .indigo
theme.primaryLightColor = .indigo.opacity(0.6)
theme.primaryDarkColor = Color(red: 0.2, green: 0.1, blue: 0.5)
// 背景
theme.commentBackgroundColor = Color(.secondarySystemGroupedBackground)
theme.containerBackgroundColor = Color(.systemGroupedBackground)
// アクションボタン
theme.actionButtonColor = .indigo
theme.replyButtonColor = .indigo
theme.toggleRepliesButtonColor = .indigo.opacity(0.8)
theme.loadMoreButtonTextColor = .indigo
// 投票
theme.voteActiveColor = .red
theme.voteCountColor = .primary
theme.voteCountZeroColor = .secondary
theme.voteDividerColor = Color(.separator)
// リンク
theme.linkColor = .indigo
theme.linkColorPressed = .indigo.opacity(0.5)
// ダイアログ
theme.dialogHeaderBackgroundColor = .indigo
theme.dialogHeaderTextColor = .white
// 入力バー
theme.inputBarBackgroundColor = Color(.systemBackground)
theme.inputBarBorderColor = Color(.separator)
// その他
theme.onlineIndicatorColor = .green
theme.separatorColor = Color(.separator)
theme.badgeBackgroundColor = .gray.opacity(0.2)
theme.threadLineColor = .indigo.opacity(0.15)
タイポグラフィ
theme.commenterNameFont = .subheadline.weight(.bold)
theme.bodyFont = .body
theme.captionFont = .caption
theme.actionFont = .caption.weight(.medium)
レイアウトと間隔
theme.cornerRadius = .large // 使用可能: .none, .small, .medium, .large
theme.commentSpacing = 4 // コメント行間のポイント数
theme.nestingIndent = 20 // ネストレベルごとのインデント量(ポイント)
theme.avatarSize = 36 // ルートコメントのアバター直径
theme.replyAvatarSize = 28 // ネストされた返信のアバター直径
視覚効果
theme.showShadows = true // カードに薄い影を表示
theme.showThreadLine = true // ネストされた返信をつなぐ垂直線
theme.animateVotes = true // 投票変更時のスプリングアニメーション
テーマの適用
2つの方法:
// SwiftUI の環境経由(ビュー階層には推奨)
FastCommentsView(sdk: sdk)
.fastCommentsTheme(theme)
// SDK に直接設定
sdk.theme = theme
カスタムツールバーのボタン 
コメント入力ツールバーのボタン
コメント入力ツールバーにボタンを追加するには、CustomToolbarButtonプロトコルを実装します:
struct EmojiButton: CustomToolbarButton {
let id = "emoji"
let iconSystemName = "face.smiling" // SF シンボル名
let contentDescription = "Add Emoji"
let badgeText: String? = nil // オプションのバッジ数
func onClick(text: Binding<String>) {
text.wrappedValue += "\u{1F44D}"
}
// オプションのオーバーライド(デフォルトは true)
func isEnabled() -> Bool { true }
func isVisible() -> Bool { true }
}
ビュー作成時にカスタムボタンを渡します:
FastCommentsView(
sdk: sdk,
customToolbarButtons: [EmojiButton(), CodeBlockButton()]
)
または SDK にグローバルに追加します(すべてのインスタンスに適用):
sdk.addGlobalCustomToolbarButton(EmojiButton())
sdk.removeGlobalCustomToolbarButton(id: "emoji")
sdk.clearGlobalCustomToolbarButtons()
フィードツールバーのボタン
投稿作成フォーム用に FeedCustomToolbarButton を実装します:
struct HashtagButton: FeedCustomToolbarButton {
let id = "hashtag"
let iconSystemName = "number"
let contentDescription = "Add Hashtag"
func onClick(content: Binding<String>) {
content.wrappedValue += "#"
}
}
作成ビューに渡します:
FeedPostCreateView(
sdk: sdk,
customToolbarButtons: [HashtagButton()],
onPostCreated: { _ in },
onCancelled: { }
)
またはフィード SDK にグローバル設定します:
sdk.globalFeedToolbarButtons = [HashtagButton()]
モデレーション 
すべてのユーザーが利用できる操作
- フラグ/フラグ解除 -- コメントを審査のために報告する
try await sdk.flagComment(commentId: commentId)
try await sdk.unflagComment(commentId: commentId)
- ブロック/ブロック解除 -- ユーザーのコメントをすべて非表示にする(閲覧者単位)
try await sdk.blockUser(commentId: commentId)
try await sdk.unblockUser(commentId: commentId)
管理者専用の操作
- ピン留め/ピン解除 -- コメントをスレッドの先頭に固定する
try await sdk.pinComment(commentId: commentId)
try await sdk.unpinComment(commentId: commentId)
- ロック/ロック解除 -- コメントへの新しい返信を禁止する
try await sdk.lockComment(commentId: commentId)
try await sdk.unlockComment(commentId: commentId)
すべてのモデレーション操作は、UI のコメントコンテキストメニューからも利用できます。管理者向けの操作は、現在のユーザーがサイト管理者である場合にのみ表示されます(SSO の isAdmin フラグまたはダッシュボードの設定で指定)。
リアルタイム更新 
sdk.load() を呼び出した後、SDK は構成された urlId の WebSocket イベントに自動的に購読します。次のイベントが処理されます:
- 新しいコメント、編集、削除
- 投票(追加および削除)
- ピン、ロック、フラグ、ブロックの状態変更
- ユーザーのプレゼンス(参加/退出)
- スレッドの開閉
- バッジ付与
- サーバー構成の更新
ライブ表示の制御
デフォルトでは、他のユーザーからの新しいコメントは即座に表示されます:
sdk.showLiveRightAway = true // デフォルト: 即座に表示
これを false に設定すると、新しいコメントが「N件の新しいコメント」ボタンの背後にバッファされ、ユーザーが表示タイミングを選べるようになります:
sdk.showLiveRightAway = false
ユーザーのプレゼンス
サーバーがプレゼンス追跡を有効にすると、ユーザーのアバター上にオンライン/オフラインのインジケーターが自動的に表示されます。クライアント側での追加設定は不要です。
ページネーション 
ページサイズ
// コメント:デフォルトは30
sdk.pageSize = 50
// フィード:デフォルトは10
feedSDK.pageSize = 20
コメントの追加読み込み
UIはページネーションコントロールを自動的に表示します。プログラムからページネーションをトリガーすることもできます:
// 次のページを読み込む
try await sdk.loadMore()
// 残りをすべて読み込む(パフォーマンスのためコメントが2000件を超える場合は無効)
try await sdk.loadAll()
// 状態を確認
sdk.hasMore // さらにページが存在するかどうか
sdk.shouldShowLoadAll()
sdk.getCountRemainingToShow()
子コメントのページネーション
ネストされた返信は遅延読み込みされます。ユーザーがスレッドを展開すると、最初の5件の子コメントが読み込まれます。さらに存在する場合は「返信をさらに読み込む」コントロールが表示されます。これはUIによって自動的に処理されます。
状態と可観測性 
FastCommentsSDK と FastCommentsFeedSDK はどちらも ObservableObject クラスで、@Published プロパティを持ちます。これらは SwiftUI のビューで監視してリアクティブな UI 更新に利用できます。
FastCommentsSDK の @Published プロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
commentCountOnServer | Int | サーバー上のコメントの総数 |
newRootCommentCount | Int | バッファされた新しいコメント(showLiveRightAway が false のとき) |
currentUser | UserSessionInfo? | 現在認証されているユーザー |
isSiteAdmin | Bool | 現在のユーザーがサイト管理者かどうか |
isClosed | Bool | コメントスレッドが閉じられているかどうか |
hasBillingIssue | Bool | 課金に問題があるかどうか |
isLoading | Bool | ネットワークリクエストが進行中かどうか |
hasMore | Bool | さらにページが存在するかどうか |
blockingErrorMessage | String? | UI の動作を妨げるエラー |
warningMessage | String? | ブロッキングしない警告メッセージ |
isDemo | Bool | デモモードで実行されているかどうか |
commentsVisible | Bool | コメント表示の切り替え |
toolbarEnabled | Bool | 書式ツールバーが表示されているかどうか |
FastCommentsFeedSDK の @Published プロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
feedPosts | [FeedPost] | 現在読み込まれているフィード投稿 |
hasMore | Bool | さらにページが存在するかどうか |
currentUser | UserSessionInfo? | 現在認証されているユーザー |
blockingErrorMessage | String? | ブロッキングエラーのメッセージ |
isLoading | Bool | ネットワークリクエストが進行中かどうか |
newPostsCount | Int | 前回の読み込み以降の新しい投稿数 |
コメントツリー
コメントツリーは sdk.commentsTree でアクセスできます:
// レンダリング用の表示されているノードのフラットな一覧
sdk.commentsTree.visibleNodes
// IDでコメントを検索
sdk.commentsTree.commentsById["comment-id"]
EUリージョン 
EU データセンターを使用するには、設定の region フィールドを設定してください:
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-page",
region: "eu"
)
これにより、すべての API リクエストと WebSocket 接続が eu.fastcomments.com にルーティングされます。
クリーンアップ 
SDKインスタンスの使用が終わったら(例: ビューが閉じられるとき)、WebSocket接続を閉じ、バックグラウンドタスクをキャンセルするためにcleanup()を呼び出してください:
sdk.cleanup()
SwiftUI の @StateObject によって管理されているビューでは、通常これは .onDisappear 内、またはビューが解放されるときに呼び出されます。
画像アップロード 
コメント
let imageUrl = try await sdk.uploadImage(imageData: jpegData, filename: "photo.jpg")
アップロードされた画像のURL文字列を返します。
フィード投稿
let mediaItem = try await feedSDK.uploadImage(imageData: jpegData, filename: "photo.jpg")
// 複数の画像を並列にアップロードする
let mediaItems = try await feedSDK.uploadImages(images: [
(jpegData1, "photo1.jpg"),
(jpegData2, "photo2.jpg")
])
ユーザーメンション 
@メンションのオートコンプリートをサポートするユーザーを検索:
let results = try await sdk.searchUsers(query: "jan")
// [UserSearchResult] を返します(userId、username、avatar など)
組み込みの CommentInputBar は @メンションのオートコンプリートを自動的に処理します。
コメントの編集と削除 
編集
try await sdk.editComment(commentId: commentId, newText: "Updated text")
サーバーがHTMLを再レンダリングします。ローカルのコメントは自動的に更新されます。
削除
try await sdk.deleteComment(commentId: commentId)
コメントを削除すると、その子孫もローカルツリーから削除されます。
これらの操作は、現在のユーザーがコメントの作成者(またはサイト管理者)の場合、UIのコメントコンテキストメニューから利用できます。
エラー処理 
SDK のメソッドは FastCommentsError をスローします。これは LocalizedError に準拠しています:
do {
try await sdk.load()
} catch let error as FastCommentsError {
print(error.translatedError ?? error.reason ?? "Unknown error")
} catch {
print(error.localizedDescription)
}
FastCommentsError のプロパティ:
code-- API からのエラーコードreason-- 英語のエラー説明translatedError-- サーバーから提供されるローカライズされたエラーメッセージ
ブロッキングエラーは sdk.blockingErrorMessage を通じて自動的に通知され、組み込みのビューがユーザーに表示します。
ヘルプが必要ですか?
iOS Library に関して問題が発生した場合や質問がある場合は、次のいずれかを行ってください:
貢献
貢献を歓迎します!コントリビューションのガイドラインについては、GitHub リポジトリをご覧ください。