From ac617900863c6b8eca568287772f6f22a3710d5e Mon Sep 17 00:00:00 2001 From: pera Date: Wed, 13 Sep 2017 11:00:04 -0300 Subject: [PATCH] Adds iOS implementation of LINE login --- example/index.android.js | 86 +++++++++ example/index.ios.js | 86 +++++++++ .../xcschemes/example-tvOS.xcscheme | 129 +++++++++++++ .../xcshareddata/xcschemes/example.xcscheme | 129 +++++++++++++ .../contents.xcworkspacedata | 10 + example/package.json | 23 +++ ios/LineLoginManager.h | 11 ++ ios/LineLoginManager.m | 176 ++++++++++++++++++ src/LineLogin.js | 42 +++++ 9 files changed, 692 insertions(+) create mode 100644 example/index.android.js create mode 100644 example/index.ios.js create mode 100644 example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme create mode 100644 example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme create mode 100644 example/ios/example.xcworkspace/contents.xcworkspacedata create mode 100644 example/package.json create mode 100644 ios/LineLoginManager.h create mode 100644 ios/LineLoginManager.m create mode 100644 src/LineLogin.js diff --git a/example/index.android.js b/example/index.android.js new file mode 100644 index 0000000..3818eb2 --- /dev/null +++ b/example/index.android.js @@ -0,0 +1,86 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + * @flow + */ + +import React, { Component } from 'react'; +import { + AppRegistry, + StyleSheet, + Text, + View, + TouchableNativeFeedback +} from 'react-native'; + +import { LoginManager } from 'react-native-line-login' + +class example extends Component { + _handleClickLogin () { + LoginManager.login() + .then((user) => { + console.log(user) + }) + .catch((err) => { + console.log(err) + }) + } + + _handleClickLogout () { + LoginManager.logout() + } + + render() { + return ( + + + Welcome to React Native! + + + To get started, edit index.android.js + + + Double tap R on your keyboard to reload,{'\n'} + Shake or press menu button for dev menu + + + + + Login + + + + + + Logout + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + welcome: { + fontSize: 20, + textAlign: 'center', + margin: 10, + }, + instructions: { + textAlign: 'center', + color: '#333333', + marginBottom: 5, + }, +}); + +AppRegistry.registerComponent('example', () => example); diff --git a/example/index.ios.js b/example/index.ios.js new file mode 100644 index 0000000..78cf9a3 --- /dev/null +++ b/example/index.ios.js @@ -0,0 +1,86 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + * @flow + */ + +import React, { Component } from 'react'; +import { + AppRegistry, + StyleSheet, + Text, + View, + TouchableHighlight +} from 'react-native'; + +import LineLogin from 'react-native-line' + +class example extends Component { + _handleClickLogin () { + LineLogin.login() + .then((user) => { + console.log(user) + }) + .catch((err) => { + console.log(err) + }) + } + + _handleClickLogout () { + LoginManager.logout() + } + + render() { + return ( + + + Welcome to React Native! + + + To get started, edit index.android.js + + + Double tap R on your keyboard to reload,{'\n'} + Shake or press menu button for dev menu + + + + + Login + + + + + + Logout + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + welcome: { + fontSize: 20, + textAlign: 'center', + margin: 10, + }, + instructions: { + textAlign: 'center', + color: '#333333', + marginBottom: 5, + }, +}); + +AppRegistry.registerComponent('example', () => example); diff --git a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme new file mode 100644 index 0000000..a36391c --- /dev/null +++ b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme new file mode 100644 index 0000000..eae9513 --- /dev/null +++ b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/example.xcworkspace/contents.xcworkspacedata b/example/ios/example.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..7f5c3aa --- /dev/null +++ b/example/ios/example.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/package.json b/example/package.json new file mode 100644 index 0000000..e2917a5 --- /dev/null +++ b/example/package.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node node_modules/react-native/local-cli/cli.js start", + "test": "jest" + }, + "dependencies": { + "react": "16.0.0-alpha.12", + "react-native": "0.48.2", + "react-native-line": "git+https://github.com/xmartlabs/react-native-line.git#master" + }, + "devDependencies": { + "babel-jest": "21.0.2", + "babel-preset-react-native": "3.0.2", + "jest": "21.0.2", + "react-test-renderer": "16.0.0-alpha.12" + }, + "jest": { + "preset": "react-native" + } +} diff --git a/ios/LineLoginManager.h b/ios/LineLoginManager.h new file mode 100644 index 0000000..07dd63c --- /dev/null +++ b/ios/LineLoginManager.h @@ -0,0 +1,11 @@ +#import + +#import + +@interface LineLoginManager : NSObject +{ + +} + +@end + diff --git a/ios/LineLoginManager.m b/ios/LineLoginManager.m new file mode 100644 index 0000000..c42d779 --- /dev/null +++ b/ios/LineLoginManager.m @@ -0,0 +1,176 @@ +#import "LineLoginManager.h" + +static NSString *errorDomain = @"LineLogin"; + +@implementation LineLoginManager +{ + LineSDKAPI *apiClient; + + RCTPromiseResolveBlock loginResolver; + RCTPromiseRejectBlock loginRejecter; +} + +- (dispatch_queue_t)methodQueue +{ + return dispatch_get_main_queue(); +} + +# pragma mark - Module + +RCT_EXPORT_MODULE() + +RCT_EXPORT_METHOD(login:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + loginResolver = resolve; + loginRejecter = reject; + + [self loginWithPermissions:nil]; +} + + +RCT_EXPORT_METHOD(loginWithPermissions:(NSArray *)permissions + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + loginResolver = resolve; + loginRejecter = reject; + + [self loginWithPermissions:permissions]; +} + +RCT_EXPORT_METHOD(currentAccessToken:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + if([[LineSDKLogin sharedInstance] isAuthorized]) + { + LineSDKAccessToken *currentAccessToken = [apiClient currentAccessToken]; + resolve([self parseAccessToken:currentAccessToken]); + } else + { + NSError *error = [[NSError alloc] initWithDomain:errorDomain code:1 userInfo:@{ NSLocalizedDescriptionKey:@"User is not logged in!" }]; + reject(nil, nil, error); + } +} + +RCT_EXPORT_METHOD(logout:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + [apiClient logoutWithCompletion:^(BOOL success, NSError * _Nullable error) { + if (success) + { + resolve(nil); + } else + { + reject(nil, nil, error); + } + }]; +} + +RCT_EXPORT_METHOD(getProfile:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + [apiClient getProfileWithCompletion:^(LineSDKProfile * _Nullable profile, NSError * _Nullable error) { + if (error) + { + reject(nil, nil, error); + } else + { + resolve([self parseProfile: profile]); + } + }]; +} + +# pragma mark - Lifecycle + +- (id) init { + self = [super init]; + if (self) + { + apiClient = [[LineSDKAPI alloc] initWithConfiguration:[LineSDKConfiguration defaultConfig]]; + [LineSDKLogin sharedInstance].delegate = self; + } + return self; +} + +- (void)loginWithPermissions:(NSArray *)permissions +{ + LineSDKLogin *shared = [LineSDKLogin sharedInstance]; + + if ([shared isAuthorized]) + { + [self getProfile:loginResolver + rejecter:loginRejecter]; + } else if ([shared canLoginWithLineApp]) + { + if (permissions && [permissions count] > 0) { + [shared startLoginWithPermissions:permissions]; + } else + { + [shared startLogin]; + } + } else + { + if (permissions && [permissions count] > 0) { + [shared startWebLoginWithSafariViewController:YES]; + } else + { + [shared startWebLoginWithSafariViewController:YES + permissions:permissions]; + } + } +} + +#pragma mark - LineSDKLoginDelegate + +- (void)didLogin:(LineSDKLogin *)login + credential:(LineSDKCredential *)credential + profile:(LineSDKProfile *)profile + error:(NSError *)error +{ + if (error) + { + loginRejecter(nil, nil, error); + } else + { + NSMutableDictionary *result = [NSMutableDictionary new]; + + NSDictionary *parsedAccessToken = [self parseAccessToken:[credential accessToken]]; + NSDictionary *parsedProfile = [self parseProfile:profile]; + + [result setValue:parsedAccessToken forKey:@"accessToken"]; + [result setValue:parsedProfile forKey:@"profile"]; + + loginResolver(result); + } +} + +#pragma mark - Helpers + +- (NSDictionary *)parseProfile:(LineSDKProfile *)profile +{ + NSMutableDictionary *result = [NSMutableDictionary new]; + + [result setValue:[profile userID] forKey:@"userID"]; + [result setValue:[profile displayName] forKey:@"displayName"]; + [result setValue:[profile statusMessage] forKey:@"statusMessage"]; + if (profile.pictureURL) + { + [result setValue:[[profile pictureURL] absoluteString] forKey:@"pictureURL"]; + } + + return result; +} + +- (NSDictionary *)parseAccessToken:(LineSDKAccessToken *)accessToken +{ + NSMutableDictionary *result = [NSMutableDictionary new]; + + [result setValue:[accessToken accessToken] forKey:@"accessToken"]; + [result setValue:[accessToken estimatedExpiredDate] forKey:@"expirationDate"]; + + return result; +} + +@end + diff --git a/src/LineLogin.js b/src/LineLogin.js new file mode 100644 index 0000000..5136265 --- /dev/null +++ b/src/LineLogin.js @@ -0,0 +1,42 @@ +import { NativeModules } from 'react-native'; + +const { LineLoginManager } = NativeModules; + +class LineLogin { + /** + * Logs the user. + */ + login = () => { + return LineLoginManager.login(); + } + + /** + * Logs the user in with the requested permissions. + */ + loginWithPermissions = (permissions) => { + return LineLoginManager.loginWithPermissions(permissions); + } + + /** + * Get the current access token. + */ + currentAccessToken = () => { + return LineLoginManager.currentAccessToken(); + } + + /** + * Get user profile. + */ + getUserProfile = () => { + return LineLoginManager.getUserProfile(); + } + + /** + * Logs out the user. + */ + logout = () => { + LineLoginManager.logout(); + } +} + +export default new LineLogin();