url : https://developers.naver.com/apps/#/wizard/register
개발테스트를 위해서 위와같이 등록을 하고 진행을 해보았습니다.
https://github.com/naver/naveridlogin-sdk-ios
Xcode에 네이버 로그인 SDK 추가하는 방법
네이버 로그인 SDK 라이브러리 설치
아래와 같이 Podfile 를 열어서 아래와 같이 추가를 해준다.
pod 'naveridlogin-sdk-ios'
info.plist 에 아래부분 추가
<string>naversearchapp</string>
<string>naversearchthirdlogin</string>
아래는 저의 환경에 넣어 놓은 상태입니다.
저는 어제 올려드렸던것처럼 kakao 와 naver login을 다 사용하기 때문입니다.
상수설정
파일의 내용을 보시면 kServiceAppUrlScheme, KConsumerKey, KConsumerSecret, kServiceAppName 을 네이버에 신청하고 받은 키값으로 변경을 해주세요.
위의 내용은 기존에 파일에 있는 내용을 그대로 옮겨서 캡쳐를 한 것이니 이 부분은 본인의 설정부분으로 변경해서 사용해 주세요.
일단 위의 내용은 IOS 에서 설정하는 것이었구요.
https://pub.dev/packages/flutter_naver_login
ios/Runner/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<!-- other codes -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>[UrlScheme]</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>naversearchapp</string>
<string>naversearchthirdlogin</string>
</array>
<key>naverServiceAppUrlScheme</key>
<string>[UrlScheme]</string>
<key>naverConsumerKey</key>
<string>[ConsumerKey]</string>
<key>naverConsumerSecret</key>
<string>[ConsumerSecret]</string>
<key>naverServiceAppName</key>
<string>[ServiceAppName]</string>
<!-- http allows configurations -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>naver.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>naver.net</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
</dict>
</plist>
위에 소스는 pub.dev에 있는 것을 가져 온것입니다. 본인에 맞게 네이버에 설정된 키값을 넣으시고 실행을 하시면 됩니다.
import 'dart:async';
import 'package:flutter/services.dart';
import 'src/clock.dart';
class FlutterNaverLogin {
static const MethodChannel _channel =
const MethodChannel('flutter_naver_login');
static Future<NaverLoginResult> logIn() async {
final Map<dynamic, dynamic> res = await _channel.invokeMethod('logIn');
return _delayedToResult(
new NaverLoginResult._(res.cast<String, dynamic>()));
}
static Future<NaverLoginResult> logOut() async {
final Map<dynamic, dynamic> res = await _channel.invokeMethod('logOut');
return _delayedToResult(
new NaverLoginResult._(res.cast<String, dynamic>()));
}
static Future<NaverLoginResult> logOutAndDeleteToken() async {
final Map<dynamic, dynamic> res = await _channel.invokeMethod('logoutAndDeleteToken');
return _delayedToResult(
new NaverLoginResult._(res.cast<String, dynamic>()));
}
static Future<bool> get isLoggedIn async {
if ((await currentAccessToken).isValid())
return true;
else
return false;
}
static Future<NaverAccountResult> currentAccount() async {
final Map<dynamic, dynamic> res =
await _channel.invokeMethod('getCurrentAcount');
return _delayedToResult(
new NaverAccountResult._(res.cast<String, dynamic>()));
}
static Future<NaverAccessToken> get currentAccessToken async {
final Map<dynamic, dynamic>? accessToken =
await _channel.invokeMethod('getCurrentAccessToken');
if (accessToken == null)
return NaverAccessToken._(noToken);
else
return _delayedToResult(
NaverAccessToken._(accessToken.cast<String, dynamic>()));
}
static Future<NaverAccessToken> refreshAccessTokenWithRefreshToken() async {
final accessToken = await currentAccessToken;
if (accessToken.refreshToken.isNotEmpty ||
accessToken.refreshToken != 'no token') {
await _channel.invokeMethod('refreshAccessTokenWithRefreshToken');
}
return (await currentAccessToken);
}
static Future<T> _delayedToResult<T>(T result) {
return new Future.delayed(const Duration(milliseconds: 100), () => result);
}
}
enum NaverLoginStatus { loggedIn, cancelledByUser, error }
class NaverLoginResult {
final NaverLoginStatus status;
final NaverAccountResult account;
final String errorMessage;
final NaverAccessToken accessToken;
NaverLoginResult._(Map<String, dynamic> map)
: status = _parseStatus(map['status'] ?? ''),
accessToken = NaverAccessToken._(map),
errorMessage = map['errorMessage'] ?? '',
account = new NaverAccountResult._(map);
static NaverLoginStatus _parseStatus(String status) {
switch (status) {
case 'loggedIn':
return NaverLoginStatus.loggedIn;
case 'cancelledByUser':
return NaverLoginStatus.cancelledByUser;
case 'error':
return NaverLoginStatus.error;
}
throw new StateError('Invalid status: $status');
}
@override
String toString() =>
'{ status: $status, account: $account, errorMessage: $errorMessage, accessToken: $accessToken }';
}
class NaverAccessToken {
final String accessToken;
final String refreshToken;
final String expiresAt;
final String tokenType;
bool isValid() {
if (expiresAt.isEmpty || expiresAt == 'no token') return false;
bool timeValid = Clock.now().isBefore(DateTime.parse(expiresAt));
bool tokenExist = accessToken.isNotEmpty && accessToken != 'no token';
return timeValid && tokenExist;
}
NaverAccessToken._(Map<String, dynamic> map)
: accessToken = map['accessToken'] ?? '',
refreshToken = map['refreshToken'] ?? '',
expiresAt = map['expiresAt'] ?? '',
tokenType = map['tokenType'] ?? '';
@override
String toString() =>
'{ accessToken: $accessToken, refreshToken: $refreshToken, expiresAt: $expiresAt, tokenType: $tokenType }';
}
class NaverAccountResult {
final String nickname;
final String id;
final String name;
final String email;
final String gender;
final String age;
final String birthday;
final String birthyear;
final String profileImage;
final String mobile;
final String mobileE164;
NaverAccountResult._(Map<String, dynamic> map)
: nickname = map['nickname'] ?? '',
id = map['id'] ?? '',
name = map['name'] ?? '',
email = map['email'] ?? '',
gender = map['gender'] ?? '',
age = map['age'] ?? '',
birthday = map['birthday'] ?? '',
birthyear = map['birthyear'] ?? '',
profileImage = map['profile_image'] ?? '',
mobile = map['mobile'] ?? '',
mobileE164 = map['mobileE164'] ?? '';
@override
String toString() {
return '{ '
'nickname: $nickname, '
'id: $id, '
'name: $name, '
'email: $email, '
'gender: $gender, '
'age: $age, '
'birthday: $birthday, '
'birthyear: $birthyear, '
'profileImage: $profileImage, '
'mobile: $mobile, '
'mobileE164: $mobileE164'
' }';
}
}
Map<String, dynamic> noToken = {
'accessToken': 'no token',
'refreshToken': 'no refreshToken',
'expiresAt': 'no token',
'tokenType': 'no token',
};
위의 소스를 실행하시면 naver로 이동하면서 실행되는 것을 알 수 있습니다.
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
var applicationResult = false
if (!applicationResult) {
applicationResult = NaverThirdPartyLoginConnection.getSharedInstance().application(app, open: url, options: options)
}
// if you use other application url process, please add code here.
if (!applicationResult) {
applicationResult = super.application(app, open: url, options: options)
}
return applicationResult
}
위의 소스는 xcode 에서 AppDelegate.swift 에 추가하셔서 저장을 해주세요.
실행된 화면
위의 예시처럼 네이버가 안 깔려 있을때는 네이버로그인 창이 뜨면서 진행이 된답니다.
flutter IOS naver login 은 여기까지 정리하였습니다.
[Flutter] Facebook Login - Android (1) | 2022.09.20 |
---|---|
[Flutter] Google Login - Android 구현 (0) | 2022.09.16 |
[Flutter]Kakao Login 구현 (0) | 2022.09.14 |
[Kakao SDK 오류] 'kakao_flutter_sdk_common/kakao_flutter_sdk_common-Swift.h' file not found (0) | 2022.09.14 |
[Polygon Testnet] MetaMask 지갑과 연결하는 방법 (0) | 2022.06.29 |