Fabricでtwitter認証
Twitterが提供しているモバイルアプリの開発プラットフォームのFabricで簡単にtwitter認証してみた。
Fabric - Twitter's Mobile Development Platform
Fabricが提供している機能
Twitter Twitter へのサインイン, Twitter API の呼び出し, View の提供, SMS 認証
Crashlytics クラッシュ統計, リアルタイム分析, テスト配信
MoPub 広告配信による収益化
SDKインポート
SDKと今回はtwitter認証だけなのでその辺をサポートしているTwitter Kitをインポート。
pod 'TwitterKit' pod 'Fabric'
セットアップ
application didFinishLaunchingWithOptions:
Twitter Kitをイニシャライズします
import Fabric import TwitterKit func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { Twitter.sharedInstance().startWithConsumerKey("your_key", consumerSecret: "your_secret") Fabric.with([Twitter.self()]) return true }
この際、Twitterにデベロッパー登録をして、自分のアプリの ConsumerKey
と consumerSecret
を取得しておく必要があります
TwitterのAPIを使用するために必要なキーを取得する手順 - Hello API
アカウント認証
デフォルトで用意されてるボタンを使いたい時
let logInButton = TWTRLogInButton(logInCompletion: { session, error in if (session != nil) { println("signed in as \(session.userName)"); } else { println("error: \(error.localizedDescription)"); } }) logInButton.center = self.view.center self.view.addSubview(logInButton)
カスタムでメソッドを使いたいとき
Twitter.sharedInstance().logInWithCompletion { session, error in if let session = session { print(session.userName) } else { print(error) } }
これで完了。
SwiftでアプリからTwitterにGif投稿
アプリで撮影した動画をgifに変換し、twitterに投稿してみた。
TwitterはGifをサポートしてるけど、既存のSLComposeViewController
や、UIActivityViewController
はgifをサポートしていないので少し面倒でした。
動画をgifに変換
Regiftというライブラリを使ったら簡単にできた
twitterに投稿
まずはActionSheet
で全アカウントを表示し、選択されたaccountを返します
import Accounts func selectAccount() -> AnyObject { let account = ACAccountStore() let accountType = account.accountTypeWithAccountTypeIdentifier(ACAccountTypeIdentifierTwitter) account.requestAccessToAccountsWithType(accountType, options: nil, completion: { (success: Bool, error: NSError!) -> Void in if success { guard let accounts = account.accountsWithAccountType(accountType) else { return } if !accounts.isEmpty { let actionSheet = UIAlertController(title: "Choose Account", message: "", preferredStyle: .ActionSheet) for account in accounts { guard let name = account.username else { return } let action = UIAlertAction(title: name, style: .Default, handler: { (action: UIAlertAction) in return account }) actionSheet.addAction(action) } self.presentViewController(actionSheet, animated: true, completion: nil) } } }) } }
選択されたアカウント、メッセージ、gifのNSDataでポスト。 メッセージはDictionaryで["status", ツイート内容]
func post(account: ACAccount, message: [String: String!], data: NSData) { let url = NSURL(string: "https://api.twitter.com/1.1/statuses/update_with_media.json") let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: .POST, URL: url, parameters: message) postRequest.account = account postRequest.addMultipartData(data, withName: "media", type: "image/gif", filename: "image.gif") postRequest.performRequestWithHandler({ (responseData: NSData!, urlResponse: NSHTTPURLResponse!, error: NSError!) -> Void in print(urlResponse) }) }
SwiftでAWS S3へデータをアップロード
AWS SDK for iOSを使ってアプリからAWS S3に動画をアップロードする処理をやってみた。 ローカルのデータをアップロードして、保存先のURLを取得します。
準備
pod 'AWSS3'
ユーザー認証の仕組みとかを実装できる Amazon CognitoというAWSサービスを登録する必要もあります。
S3の設定 Bucketを作成します。 permissionはとりあえず、EveryOne が UploadとRead できるようにしておきます。
これで準備完了。
実装
application:didFinishLaunchingWithOptions
でCognitoを使ってSDKのセットアップ
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: RegionType, identityPoolId: IdentityPoolId) let configuration = AWSServiceConfiguration(region: DefaultServiceRegionType, credentialsProvider: credentialsProvider) AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
実際にアップロードするところは
internal func upload() -> NSURL { let uploadRequest = AWSS3TransferManagerUploadRequest() uploadRequest.body = origin uploadRequest.key = remote uploadRequest.bucket = BucketName let transferManager = AWSS3TransferManager.defaultS3TransferManager() transferManager.upload(uploadRequest).continueWithBlock { task -> AnyObject! in if task.result != nil { if let bucket = uploadRequest.bucket, key = uploadRequest.key { let url = NSURL(string: "http://s3.amazonaws.com/\(bucket)/\(key)") return url } } } }
origin
にアップロードするデータのfilepath、remote
にS3に保存するデータの名前を入れます。
アップロードが成功すると保存先のURLが返ってきます。
使いやすいように、SwiftTaskを使ってこんな感じのクラスを作ってみた
import AWSS3 import SwiftTask class S3Uploader { typealias UploadTask = Task<Void, NSURL, NSError> private var origin: NSURL? private var remote: String? internal init(origin: NSURL, remote: String) { self.origin = origin self.remote = remote } internal func upload() -> UploadTask { return UploadTask { progress, fulfill, reject, configure in guard let origin = self.origin, remote = self.remote else { return } let uploadRequest = AWSS3TransferManagerUploadRequest() uploadRequest.body = origin uploadRequest.key = remote uploadRequest.bucket = AppConfig.AWSS3.BucketName let transferManager = AWSS3TransferManager.defaultS3TransferManager() transferManager.upload(uploadRequest).continueWithBlock { task -> AnyObject! in if let error = task.error { reject(error) } if task.result != nil { if let bucket = uploadRequest.bucket, key = uploadRequest.key { if let url = NSURL(string: "http://s3.amazonaws.com/\(bucket)/\(key)") { fulfill(url) } } } return nil } } } }
けっこう頻繁に更新されている公式のサンプルもあって、参考になった。(日本人の方がつくってるっぽい)
SwiftでLINEの桜が降るエフェクトを作ってみた
LINE桜降ってる🌸 pic.twitter.com/JPoHU7hH6k
— ゆづちゃん Luce/BÜMP (@ahonekoyuzuchan) 2016年4月1日
これです。
ほんとはLINEに実装される前にCocoaPodsになにか公開しようと思って作ったものなんだけど...
CoreAnimation
のパーティクルシステム、CAEmitterLayer
とCAEmmiterCell
を使ってけっこう簡単にできました。
桜の他にも、タンポポとPlumも選べるようにした
SwiftでSnapChatっぽいUI
SwiftでSnapChatぽいUI、左右のスワイプでViewControllerが切り替わるやつをやってみた。
まずは大元となるContainerViewController
を作って(Containerという名前が正しいかはわからないけど)、その上に敷いたScrollView
にVCたちをaddChildViewController
していく感じ。
class ContainerViewController: UIViewController { private var offset = 0 private var viewControllers = [UIViewController]() internal init(controllers: [UIViewController], offset: Int) { super.init(nibName: nil, bundle: nil) controllers.forEach { viewControllers.append($0) } self.offset = offset } private func setupScrollView() { let viewBounds = self.view.bounds let viewWidth = viewBounds.width let scrollView = UIScrollView() scrollView.delegate = self scrollView.pagingEnabled = true scrollView.showsHorizontalScrollIndicator = false scrollView.bounces = false scrollView.frame = CGRect(x: viewBounds.origin.x, y: viewBounds.origin.y, width: viewWidth, height: CGRectGetHeight(viewBounds)) self.view.addSubview(scrollView) scrollView.contentSize = CGSize(width: CGFloat(viewControllers.count) * viewWidth, height: CGRectGetHeight(viewBounds)) for (index, vc) in viewControllers.enumerate() { vc.view.frame = CGRect(x: CGFloat(index)*viewWidth, y: 0, width: viewWidth, height: CGRectGetHeight(viewBounds)) self.addChildViewController(vc) scrollView.addSubview(vc.view) vc.didMoveToParentViewController(self) scrollView.sendSubviewToBack(vc.view) } scrollView.contentOffset.x = viewControllers[offset].view.frame.origin.x } }
ContainerViewController
の初期化はアプリ起動時にこんな感じで行ってる。
internal func setup(application: UIApplication) { let cameraSB = UIStoryboard(name: "Camera", bundle: nil) let feedSB = UIStoryboard(name: "Feed", bundle: nil) let profileSB = UIStoryboard(name: "Profile", bundle: nil) let camera = cameraSB.instantiateViewControllerWithIdentifier("camera") let feed = feedSB.instantiateViewControllerWithIdentifier("feed") let profile = profileSB.instantiateViewControllerWithIdentifier("profile") let controllers = [feed, camera, profile] let container = ContainerViewController(controllers: controllers, offset: 1) self.window?.rootViewController = container self.window?.makeKeyAndVisible() }
(実際のコードから削っているのでそのままだと動かないかもしれないです)
Swiftで動画編集
swiftで動画(AVAsset)を逆再生や、早送りにして書き出すのをやってみた。
方法としては、
AVAsset
を[CGImage]
に変換する- それを並び替えたりして、
CAKeyframeAnimation
を仕込んだCALayer
に変換する addSublayer
でプレビューする- MOVとして書き出す
まずは、動画を画像配列に変換
extension AVAsset { func frames() -> [CGImage] { var images = [CGImage]() guard let track = tracksWithMediaType(AVMediaTypeVideo).first else { return [CGImage]() } var reader: AVAssetReader? do { reader = try AVAssetReader(asset: self) } catch let error as NSError { print(error) } let options = [ "\(kCVPixelBufferPixelFormatTypeKey)": Int(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) ] let output = AVAssetReaderTrackOutput(track: track, outputSettings: options) reader?.addOutput(output) reader?.startReading() while let sample = output.copyNextSampleBuffer() { guard let pixelBuffer = CMSampleBufferGetImageBuffer(sample) else { return [CGImage]() } let ciImage = CIImage(CVPixelBuffer: pixelBuffer) let context = CIContext(options: [kCIContextUseSoftwareRenderer: true]) let cgImage = context.createCGImage(ciImage, fromRect: ciImage.extent) images.append(cgImage) } return images } }
次にその画像配列を並び替えたりして、アニメーションレイヤーを作成
任意の画像とdurationのセットで渡します
struct KeyFrame { internal let image: CGImage internal let duration: Double }
extension CALayer { class func animation(keyFrames: [KeyFrame]) -> CALayer { let total = keyFrames.map({ $0.duration }).reduce(0, combine: +) let count = keyFrames.count var times = [Double]() var currentTime = 0.0 for i in 0..<count { times.append(currentTime/total) currentTime += keyFrames[i].duration } let layer = CALayer() let animation = CAKeyframeAnimation(keyPath: "contents") animation.keyTimes = times animation.values = keyFrames.map { $0.image } animation.duration = total animation.repeatCount = .infinity animation.beginTime = AVCoreAnimationBeginTimeAtZero animation.removedOnCompletion = false animation.calculationMode = kCAAnimationDiscrete layer.addAnimation(animation, forKey: "contents") return layer } }
これであとは、
let animationLayer = layer.animation(keyFrames) layer.frame = view.frame previewView.layer.addSublayer(layer)
みたいな感じでプレビユーできた!
最後書き出しはAVAssetExportSession
で簡単!