From 93063eaf7ad1a83c54cbb242b92f2840be48ae0f Mon Sep 17 00:00:00 2001 From: banjun Date: Sun, 15 Mar 2015 17:26:00 +0900 Subject: [PATCH 1/2] add twitter auth view --- AsakusaSatellite.podspec | 8 +- Classes/Client.swift | 13 +- Classes/iOS/TwitterAuthViewController.swift | 114 ++++++++++++++++++ .../ViewController.swift | 19 ++- Example/Podfile.lock | 7 +- 5 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 Classes/iOS/TwitterAuthViewController.swift diff --git a/AsakusaSatellite.podspec b/AsakusaSatellite.podspec index 5487dfb..c7008c8 100644 --- a/AsakusaSatellite.podspec +++ b/AsakusaSatellite.podspec @@ -11,9 +11,15 @@ Pod::Spec.new do |s| s.ios.deployment_target = "8.0" # s.osx.deployment_target = "10.10" s.source = { :git => "https://github.com/codefirst/AsakusaSatelliteSwiftClient.git", :tag => "0.0.1" } - s.source_files = "Classes", "Classes/**/*.{h,m,swift}" + s.source_files = "Classes/*.swift" s.requires_arc = true s.dependency "Alamofire", "~> 1.1" s.dependency "SwiftyJSON", "~> 2.1" s.dependency "Socket.IO-Client-Swift", "~> 1.1" + + s.subspec 'iOS' do |ss| + ss.ios.deployment_target = '8.0' + ss.ios.source_files = 'Classes/iOS/*.swift' + ss.osx.source_files = '' + end end diff --git a/Classes/Client.swift b/Classes/Client.swift index a8ebca5..1de5a0a 100644 --- a/Classes/Client.swift +++ b/Classes/Client.swift @@ -12,15 +12,16 @@ import SwiftyJSON public class Client { - let baseURL: String + public let rootURL: String + var apiBaseURL: String { return "\(rootURL)/api/v1" } let apiKey: String? public convenience init(apiKey: String?) { - self.init(baseURL: "https://asakusa-satellite.herokuapp.com/api/v1", apiKey: apiKey) + self.init(rootURL: "https://asakusa-satellite.herokuapp.com", apiKey: apiKey) } - public init(baseURL: String, apiKey: String?) { - self.baseURL = baseURL + public init(rootURL: String, apiKey: String?) { + self.rootURL = rootURL self.apiKey = apiKey // remove all AasakusaSatellite cookies @@ -30,7 +31,7 @@ public class Client { private func removeCookies() { let cs = NSHTTPCookieStorage.sharedHTTPCookieStorage() - for cookie in (cs.cookiesForURL(NSURL(string: baseURL)!) as? [NSHTTPCookie]) ?? [] { + for cookie in (cs.cookiesForURL(NSURL(string: rootURL)!) as? [NSHTTPCookie]) ?? [] { cs.deleteCookie(cookie) } } @@ -74,7 +75,7 @@ public class Client { // MARK: - private func request(endpoint: Endpoint, completion: Response -> Void) { - Alamofire.request(endpoint.URLRequest(baseURL, apiKey: apiKey)).responseJSON { (request, response, object, error) -> Void in + Alamofire.request(endpoint.URLRequest(apiBaseURL, apiKey: apiKey)).responseJSON { (request, response, object, error) -> Void in if object == nil || error != nil { NSLog("failure in Client.request(\(endpoint)): \(error)") completion(.Failure(error)) diff --git a/Classes/iOS/TwitterAuthViewController.swift b/Classes/iOS/TwitterAuthViewController.swift new file mode 100644 index 0000000..17a23b3 --- /dev/null +++ b/Classes/iOS/TwitterAuthViewController.swift @@ -0,0 +1,114 @@ +// +// TwitterAuthViewController.swift +// AsakusaSatelliteSwiftClient +// +// Created by BAN Jun on 2015/03/15. +// Copyright (c) 2015年 codefirst. All rights reserved. +// + +import Foundation +import UIKit + + +private let kAuthTwitterPath = "/auth/twitter" +private let kAccountPath = "/account" + + +public class TwitterAuthViewController: UIViewController, UIWebViewDelegate { + let webview = UIWebView(frame: CGRectZero) + let rootURL: NSURL + let completion: (String? -> Void) + + // MARK: init + + public init(rootURL: NSURL, completion: (String? -> Void)) { + self.rootURL = rootURL + self.completion = completion + super.init(nibName: nil, bundle: nil) + } + + required public init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - + + public override func viewDidLoad() { + title = NSLocalizedString("Sign in with Twitter", comment: "") + + webview.autoresizingMask = .FlexibleWidth | .FlexibleHeight + webview.frame = view.bounds + webview.delegate = self + view.addSubview(webview) + + if let url = NSURL(string: kAuthTwitterPath, relativeToURL: rootURL) { + // load /auth/twitter with referer /account + // oauth callback redirects to referer + let request = NSMutableURLRequest(URL: url) + request.setValue(kAccountPath, forHTTPHeaderField: "Referer") + webview.loadRequest(request) + } else { + let ac = UIAlertController( + title: NSLocalizedString("Cannot Load", comment: ""), + message: NSLocalizedString("Invalid URL: ", comment: "") + "\(rootURL)", + preferredStyle: .Alert) + ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: { _ in + ac.dismissViewControllerAnimated(true, completion: nil) + })) + self.presentViewController(ac, animated: true, completion: nil) + } + } + + // MARK: UIWebViewDelegate + + private func isRedirectedBackToAsakusaSatellite(request: NSURLRequest) -> Bool { + let reqURLString = request.URL.absoluteString + let rootURLString = rootURL.absoluteString! + + return reqURLString?.hasPrefix(rootURLString) == true && request.URL.path == kAccountPath + } + + public func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { + if isRedirectedBackToAsakusaSatellite(request) { + // TODO: display HUD + NSLog("Getting API Key...") + } + return true + } + + public func webViewDidStartLoad(webView: UIWebView) { + UIApplication.sharedApplication().networkActivityIndicatorVisible = true + } + + public func webViewDidFinishLoad(webView: UIWebView) { + UIApplication.sharedApplication().networkActivityIndicatorVisible = false + + if isRedirectedBackToAsakusaSatellite(webview.request!) { + // did load /account on AsakusaSatellite + // TODO: display HUD + NSLog("Completed") + + // get apiKey from text field + let js = "$('#account_secret_key').attr('value')" + let apiKey = webview.stringByEvaluatingJavaScriptFromString(js) + + webView.delegate = nil // unlink delegate before removing self + navigationController?.popViewControllerAnimated(true) + completion((apiKey?.isEmpty ?? true) ? nil : apiKey) + } + } + + public func webView(webView: UIWebView, didFailLoadWithError error: NSError) { + UIApplication.sharedApplication().networkActivityIndicatorVisible = false + + let ac = UIAlertController( + title: NSLocalizedString("Cannot Load", comment: ""), + message: error.localizedDescription, + preferredStyle: .Alert) + ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: { _ in + ac.dismissViewControllerAnimated(true, completion: nil) + })) + self.presentViewController(ac, animated: true, completion: nil) + } +} + diff --git a/Example/AsakusaSatelliteSwiftClientExample/ViewController.swift b/Example/AsakusaSatelliteSwiftClientExample/ViewController.swift index 3fb95d4..7dbcf9d 100644 --- a/Example/AsakusaSatelliteSwiftClientExample/ViewController.swift +++ b/Example/AsakusaSatelliteSwiftClientExample/ViewController.swift @@ -46,6 +46,8 @@ class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate listButton.addTarget(self, action: "list:", forControlEvents: .TouchUpInside) messagesTextView.delegate = self + navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Sign in", style: .Plain, target: self, action: "signin:") + let views = [ "apiKey": apiKeyField, "name": usernameLabel, @@ -82,7 +84,7 @@ class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate let apiKey = NSUserDefaults.standardUserDefaults().objectForKey(kDefaultsKeyApiKey) as? String apiKeyField.text = apiKey client = AsakusaSatellite.Client(apiKey: apiKey) - // client = AsakusaSatellite.Client(baseURL: "http://localhost:3000/api/v1", apiKey: apiKey) + // client = AsakusaSatellite.Client(rootURL: "http://localhost:3000", apiKey: apiKey) NSLog("initialized client with apiKey = \(apiKey)") usernameLabel.text = "(initialized)" @@ -144,6 +146,21 @@ class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate } } + func signin(sender: AnyObject?) { + let vc = TwitterAuthViewController(rootURL: NSURL(string: client.rootURL)!) { [weak self] apiKey in + let defaults = NSUserDefaults.standardUserDefaults() + if let apiKey = apiKey { + defaults.setObject(apiKey, forKey: kDefaultsKeyApiKey) + } else { + NSLog("cannot sign in") + defaults.removeObjectForKey(kDefaultsKeyApiKey) + } + defaults.synchronize() + self?.reloadClient() + } + navigationController?.pushViewController(vc, animated: true) + } + // MARK: - TextField func textFieldShouldReturn(textField: UITextField) -> Bool { diff --git a/Example/Podfile.lock b/Example/Podfile.lock index e6b62ca..669dfe5 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,6 +1,11 @@ PODS: - Alamofire (1.1.4) - AsakusaSatellite (0.0.1): + - Alamofire (~> 1.1) + - AsakusaSatellite/iOS (= 0.0.1) + - Socket.IO-Client-Swift (~> 1.1) + - SwiftyJSON (~> 2.1) + - AsakusaSatellite/iOS (0.0.1): - Alamofire (~> 1.1) - Socket.IO-Client-Swift (~> 1.1) - SwiftyJSON (~> 2.1) @@ -16,7 +21,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Alamofire: 524225da382071ee3e6d0badd0ee4b4dc36740de - AsakusaSatellite: e7082b74b819a4436ccb0efa522ed93e94406b74 + AsakusaSatellite: cb907d6e78a5fae603aac0166341c2004b544b96 Socket.IO-Client-Swift: 23d9f0db0cdcb98623486ddf0ee811b158e9cd02 SwiftyJSON: 48be7490a3989a58a3f511cd54167f0a2b466e76 From bc8b06006325fe2e2775db8b3088c45994f5af41 Mon Sep 17 00:00:00 2001 From: banjun Date: Sun, 15 Mar 2015 17:45:39 +0900 Subject: [PATCH 2/2] not include ios classes for platform :osx --- AsakusaSatellite.podspec | 12 ++++-------- Classes/{iOS => ios}/TwitterAuthViewController.swift | 0 Example/Podfile.lock | 7 +------ 3 files changed, 5 insertions(+), 14 deletions(-) rename Classes/{iOS => ios}/TwitterAuthViewController.swift (100%) diff --git a/AsakusaSatellite.podspec b/AsakusaSatellite.podspec index c7008c8..dcd3311 100644 --- a/AsakusaSatellite.podspec +++ b/AsakusaSatellite.podspec @@ -9,17 +9,13 @@ Pod::Spec.new do |s| s.license = "MIT" s.author = { "banjun" => "banjun@gmail.com" } s.ios.deployment_target = "8.0" - # s.osx.deployment_target = "10.10" + s.osx.deployment_target = "10.10" s.source = { :git => "https://github.com/codefirst/AsakusaSatelliteSwiftClient.git", :tag => "0.0.1" } - s.source_files = "Classes/*.swift" + s.source_files = 'Classes/*.swift' + s.ios.source_files = 'Classes/ios/*.swift' + s.osx.source_files = '' s.requires_arc = true s.dependency "Alamofire", "~> 1.1" s.dependency "SwiftyJSON", "~> 2.1" s.dependency "Socket.IO-Client-Swift", "~> 1.1" - - s.subspec 'iOS' do |ss| - ss.ios.deployment_target = '8.0' - ss.ios.source_files = 'Classes/iOS/*.swift' - ss.osx.source_files = '' - end end diff --git a/Classes/iOS/TwitterAuthViewController.swift b/Classes/ios/TwitterAuthViewController.swift similarity index 100% rename from Classes/iOS/TwitterAuthViewController.swift rename to Classes/ios/TwitterAuthViewController.swift diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 669dfe5..05dc2ad 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,11 +1,6 @@ PODS: - Alamofire (1.1.4) - AsakusaSatellite (0.0.1): - - Alamofire (~> 1.1) - - AsakusaSatellite/iOS (= 0.0.1) - - Socket.IO-Client-Swift (~> 1.1) - - SwiftyJSON (~> 2.1) - - AsakusaSatellite/iOS (0.0.1): - Alamofire (~> 1.1) - Socket.IO-Client-Swift (~> 1.1) - SwiftyJSON (~> 2.1) @@ -21,7 +16,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Alamofire: 524225da382071ee3e6d0badd0ee4b4dc36740de - AsakusaSatellite: cb907d6e78a5fae603aac0166341c2004b544b96 + AsakusaSatellite: 499c3117a42e276856fbd04608e38d40718b1c71 Socket.IO-Client-Swift: 23d9f0db0cdcb98623486ddf0ee811b158e9cd02 SwiftyJSON: 48be7490a3989a58a3f511cd54167f0a2b466e76