Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getFriends feature in social #9

Merged
merged 1 commit into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions docs/docs/social/get-friends.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
sidebar_position: 4
---

# 카카오톡 친구 가져오기
## 카카오톡 친구 가져오기

[공식 문서](https://developers.kakao.com/docs/latest/ko/kakaotalk-social/android#get-friends)

:::info
API를 사용하기 위해서 카카오 로그인 및 관련 동의 항목이 동의된 상태여야 합니다.

피커와 친구 목록 가져오기 API는 사용 권한이 주어진 앱에서만 사용할 수 있습니다.
:::

현재 로그인한 사용자의 카카오톡 친구 목록을 불러옵니다.
요청 시 친구 목록의 정렬 순서, 한 페이지당 친구 수를 선택적으로 지정할 수 있습니다. 파라미터 없이 요청 시 기본 설정대로 요청이 전송됩니다.

## Usage

`getFriends()`를 이용해 친구 목록을 가져올 수 있습니다.

다음과 같이 정의되어 있습니다.

```tsx
export function getFriends(params: {
options?: KakaoTalkGetFriendsOptions;
}): Promise<KakaoTalkGetFriendsResult>
```

사용되는 타입들은 다음과 같습니다.

```tsx
/**
* 카카오톡 친구
*
* @property id 회원번호
* @property uuid 메시지를 전송하기 위한 고유 아이디. 사용자의 계정 상태에 따라 이 정보는 바뀔 수 있으므로 앱내의 사용자 식별자로는 권장하지 않음.
* @property profileNickname 친구의 닉네임
* @property profileThumbnailImage 썸네일 이미지 URL
* @property favorite 즐겨찾기 추가 여부
* @property allowedMsg 메시지 수신이 허용되었는지 여부. 앱가입 친구의 경우는 feed msg 에 해당. 앱미가입친구는 invite msg 에 해당
*/
export interface KakaoTalkFriend {
id?: number;
uuid: string;
profileNickname: string;
profileThumbnailImage?: string;
favorite?: boolean;
allowedMsg?: boolean;
}

export interface KakaoTalkGetFriendsOptions {
offset?: number;
limit?: number;
order?: 'asc' | 'desc';
friendOrder?: 'nickname' | 'age' | 'favorite';
}
```
2 changes: 1 addition & 1 deletion docs/docs/social/get-talk-profile.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 2
---

# 내 카카오톡 프로필 가져오기
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/social/select-talk-friends.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 3
---

# 카카오톡 친구 선택하기
Expand Down
4 changes: 2 additions & 2 deletions example/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@
"https://devrepo.kakao.com/nexus/content/groups/public/"
],
"minSdkVerson": 26,
"newArchEnabled": false
"newArchEnabled": true
},
"ios": {
"newArchEnabled": false
"newArchEnabled": true
}
}
],
Expand Down
9 changes: 9 additions & 0 deletions example/src/app/social.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from 'react';
import { showMessage } from 'react-native-flash-message';
import { formatJson } from '@mj-studio/js-util';
import {
getFriends,
getTalkProfile,
type KakaoTalkProfile,
selectMultipleFriends,
Expand Down Expand Up @@ -54,6 +55,14 @@ export default function Page() {
.catch((e) => showMessage({ type: 'warning', message: e.message }))
}
/>
<Btn
title={'Get Friends'}
onPress={() =>
getFriends({ options: {} })
.then((res) => showMessage({ message: formatJson(res) }))
.catch((e) => showMessage({ type: 'warning', message: e.message }))
}
/>
</StyledScrollView>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import com.kakao.sdk.friend.model.ViewAppearance.AUTO
import com.kakao.sdk.friend.model.ViewAppearance.DARK
import com.kakao.sdk.friend.model.ViewAppearance.LIGHT
import com.kakao.sdk.talk.TalkApiClient
import com.kakao.sdk.talk.model.FriendOrder
import com.kakao.sdk.talk.model.Order
import net.mjstudio.rnkakao.core.util.RNCKakaoResponseNotFoundException
import net.mjstudio.rnkakao.core.util.argArr
import net.mjstudio.rnkakao.core.util.argMap
Expand Down Expand Up @@ -133,6 +135,58 @@ class RNCKakaoSocialModule internal constructor(context: ReactApplicationContext
minPickableCount = options?.getIntElseNull("minPickableCount"),
)

@ReactMethod
override fun getFriends(
options: ReadableMap?,
promise: Promise,
) = onMain {
TalkApiClient.instance.friends(
offset = options?.getIntElseNull("offset"),
limit = options?.getIntElseNull("limit"),
order =
when (options?.getString("order")) {
"asc" -> Order.ASC
"desc" -> Order.DESC
else -> null
},
friendOrder =
when (options?.getString("friendOrder")) {
"nickname" -> FriendOrder.NICKNAME
"age" -> FriendOrder.AGE
"favorite" -> FriendOrder.FAVORITE
else -> null
},
) { friends, error ->
if (error != null) {
promise.rejectWith(error)
} else if (friends?.elements == null) {
promise.rejectWith(RNCKakaoResponseNotFoundException("friends"))
} else {
promise.resolve(
argMap().apply {
putInt("totalCount", friends.totalCount)
putIntIfNotNull("favoriteCount", friends.favoriteCount)
putArray(
"friends",
argArr().pushMapList(
friends.elements!!.map {
argMap().apply {
putIntIfNotNull("id", it.id?.toInt())
putString("uuid", it.uuid)
putString("profileNickname", it.profileNickname)
putString("profileThumbnailImage", it.profileThumbnailImage)
putBooleanIfNotNull("favorite", it.favorite)
putBooleanIfNotNull("allowedMsg", it.allowedMsg)
}
},
),
)
},
)
}
}
}

companion object {
const val NAME = "RNCKakaoSocial"
}
Expand Down
5 changes: 5 additions & 0 deletions packages/social/android/src/oldarch/KakaoSocialSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ abstract class KakaoSocialSpec internal constructor(context: ReactApplicationCon
options: ReadableMap?,
promise: Promise,
)

abstract fun getFriends(
options: ReadableMap?,
promise: Promise,
)
}
22 changes: 16 additions & 6 deletions packages/social/ios/RNCKakaoSocial.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,28 @@ - (RNCKakaoSocialManager*)manager {

RCT_EXPORT_MODULE()

- (void)getProfile:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
RCT_EXPORT_METHOD(getProfile
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject) {
[[self manager] getProfile:resolve reject:reject];
}

- (void)selectFriends:(BOOL)multiple
mode:(NSString*)mode
options:(NSDictionary*)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
RCT_EXPORT_METHOD(selectFriends
: (BOOL)multiple mode
: (NSString*)mode options
: (NSDictionary*)options resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject) {
[[self manager] selectFriends:multiple mode:mode options:options resolve:resolve reject:reject];
}

RCT_EXPORT_METHOD(getFriends
: (NSDictionary*)options resolve
: (RCTPromiseResolveBlock)resolve reject
: (RCTPromiseRejectBlock)reject) {
[[self manager] getFriendsWithOptions:options resolve:resolve reject:reject];
}

// Don't compile this code when we build for the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
Expand Down
85 changes: 50 additions & 35 deletions packages/social/ios/RNCKakaoSocialManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,41 +32,6 @@ import RNCKakaoCore
}
}

@objc public func getFriends(
options: [String: Any],
resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock
) {
let order: Order? = switch options["order"] {
case let x as String where x == "asc": .Asc
case let x as String where x == "desc": .Desc
default: nil
}
let friendOrder: FriendOrder? = switch options["friendOrder"] {
case let x as String where x == "nickname": .Nickname
case let x as String where x == "age": .Age
case let x as String where x == "favorite": .Favorite
default: nil
}

onMain {
TalkApi.shared
.friends(
offset: options["offset"] as? Int,
limit: options["limit"] as? Int,
order: order,
friendOrder: friendOrder
) { friends, error in
if let error {
RNCKakaoUtil.reject(reject, error)
} else if let friends {
} else {
RNCKakaoUtil.reject(reject, RNCKakaoError.responseNotFound(name: "friends"))
}
}
}
}

@objc public func selectFriends(
_ multiple: Bool,
mode: String,
Expand Down Expand Up @@ -138,6 +103,56 @@ import RNCKakaoCore
}
}
}

@objc public func getFriends(
options: [String: Any],
resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock
) {
let order: Order? = switch options["order"] {
case let x as String where x == "asc": .Asc
case let x as String where x == "desc": .Desc
default: nil
}
let friendOrder: FriendOrder? = switch options["friendOrder"] {
case let x as String where x == "nickname": .Nickname
case let x as String where x == "age": .Age
case let x as String where x == "favorite": .Favorite
default: nil
}

onMain {
TalkApi.shared
.friends(
offset: options["offset"] as? Int,
limit: options["limit"] as? Int,
order: order,
friendOrder: friendOrder
) { friends, error in
if let error {
RNCKakaoUtil.reject(reject, error)
} else if let friends, let items = friends.elements {
resolve([
"totalCount": friends.totalCount,
"favoriteCount": friends.favoriteCount as Any,
"friends": items
.map {
[
"id": $0.id as Any,
"uuid": $0.uuid,
"profileNickname": $0.profileNickname as Any,
"profileThumbnailImage": $0.profileThumbnailImage as Any,
"favorite": $0.favorite as Any,
"allowedMsg": $0.allowedMsg as Any
]
}
])
} else {
RNCKakaoUtil.reject(reject, RNCKakaoError.responseNotFound(name: "friends"))
}
}
}
}
}

/// /// 친구 피커의 이름
Expand Down
17 changes: 16 additions & 1 deletion packages/social/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { NativeModules, Platform } from 'react-native';

import type {
KakaoTalkFriend,
KakaoTalkFriendProfile,
KakaoTalkFriendSelectOptions,
KakaoTalkFriendSelectResult,
KakaoTalkGetFriendsOptions,
KakaoTalkGetFriendsResult,
KakaoTalkProfile,
Spec,
} from './spec/NativeKakaoSocial';
Expand All @@ -12,7 +16,10 @@ export type {
KakaoTalkFriendProfile,
KakaoTalkFriendSelectOptions,
KakaoTalkFriendSelectResult,
} from './spec/NativeKakaoSocial';
KakaoTalkGetFriendsOptions,
KakaoTalkFriend,
KakaoTalkGetFriendsResult,
};

const LINKING_ERROR =
"The package '@react-native-kakao/social' doesn't seem to be linked. Make sure: \n\n" +
Expand Down Expand Up @@ -63,3 +70,11 @@ export function selectMultipleFriends({
}) {
return Native.selectFriends(true, mode, options);
}

export function getFriends({
options = {},
}: {
options?: KakaoTalkGetFriendsOptions;
}): Promise<KakaoTalkGetFriendsResult> {
return Native.getFriends(options);
}
Loading
Loading