アプリからCloudFrontにアクセスする際に署名付きCookieを使用したかったので試してみた
サーバ側でCloudFrontから署名付きcookieを取得し
「CloudFront-Policy」「CloudFront-Signature」「CloudFront-Key-Pair-Id」
をアプリ側に渡している状態を前提としている
画像の場合
サンプルコード (Android)
画像リクエストにCookieを設定する画像ライブラリとしてFrescoとGlideがあったが、Glideの方がささっと実装できそうだったのでGlideを選択した
外部アクセスするのでマニフェストファイルに以下パーミッションを追加
<uses-permission android:name="android.permission.INTERNET" />
- MainActivity.java
package com.example.makotokawano.imagetest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.Headers;
import com.bumptech.glide.load.model.LazyHeaders;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView matchImage = findViewById(R.id.match_image);
String url = "[CloudFrontコンテンツURL]";
//cookieに「CloudFront-Policy」「CloudFront-Signature」「CloudFront-Key-Pair-Id」の
//3パラメーターが必要
String cookie =
"CloudFront-Policy=" + "XXXX" + ";"
+ "CloudFront-Signature=" + "XXXX" + ";"
+ "CloudFront-Key-Pair-Id=" + "XXXX" + ";";
Headers headers = new LazyHeaders.Builder()
.addHeader("Cookie", cookie)
.build();
Glide.with(this).load(new GlideUrl(url, headers)).into(matchImage);
}
}
- activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark"
tools:context=".MainActivity"
>
<ImageView
android:id="@+id/match_image"
android:layout_width="200dp"
android:layout_height="200dp" />
</LinearLayout>
サンプルコード(Swift)
UIImageViewをカスタマイズする
(参考: https://qiita.com/nbapps_dev/items/d22837b04d8bb0a3127d )
import Foundation
import UIKit
class SimpleAsyncImageView: UIImageView {
//画像を非同期で読み込む
func loadImage(urlString: String){
var req = URLRequest(url: NSURL(string:urlString)! as URL)
//cookieをセット
let cookieValue =
"CloudFront-Policy=" + "XXXX" + ";"
+ "CloudFront-Signature=" + "XXXX" + ";"
+ "CloudFront-Key-Pair-Id=" + "XXXX" + ";"
req.setValue(cookieValue, forHTTPHeaderField: "Cookie")
let conf = URLSessionConfiguration.default;
let session = URLSession(configuration: conf, delegate: nil, delegateQueue: OperationQueue.main);
session.dataTask(with: req, completionHandler:
{ (data, resp, err) in
if((err) == nil){ //Success
let image = UIImage(data:data!)
self.image = image;
}else{ //Error
print("AsyncImageView:Error \(err?.localizedDescription)");
}
}).resume();
}
}
動画の場合
サンプルコード (Android)
- MainActivity.java
package com.example.makotokawano.imagetest;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.VideoView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.Headers;
import com.bumptech.glide.load.model.LazyHeaders;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//cookieに「CloudFront-Policy」「CloudFront-Signature」「CloudFront-Key-Pair-Id」の
//3パラメーターが必要
String cookie =
"CloudFront-Policy=" + "XXXX" + ";"
+ "CloudFront-Signature=" + "XXXX" + ";"
+ "CloudFront-Key-Pair-Id=" + "XXXX" + ";";
VideoView videoView = findViewById(R.id.video_view);
Map<String, String> videoHeaders = new HashMap<String, String>();
videoHeaders.put("Cookie", cookie);
videoView.setVideoURI(Uri.parse("[CloudFrontコンテンツURL]"), videoHeaders);
videoView.setMediaController(new MediaController(this));
videoView.start();
}
}
- acitivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark"
tools:context=".MainActivity"
android:orientation="vertical"
>
<VideoView
android:id="@+id/video_view"
android:layout_width="200dp"
android:layout_height="200dp"
/>
</LinearLayout>
サンプルコード (Swift)
この辺の記事を参考にした
- ViewController.swift
import UIKit
import AVKit
import AVFoundation
import CoreMedia
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.setTitle("Play", for: .normal)
button.addTarget(self, action: #selector(self.onClick(_:)), for: .touchUpInside)
button.sizeToFit()
button.center = self.view.center
self.view.addSubview(button)
}
@objc func onClick(_ sender: AnyObject) {
// Do any additional setup after loading the view, typically from a nib.
let url = URL(string: "[CloudFrontコンテンツURL]")
let cookieStr1 = "CloudFront-Policy=" + "XXXX"
let cookieStr2 = "CloudFront-Signature=" + "XXXX"
let cookieStr3 = "CloudFront-Key-Pair-Id=" + "XXXX"
let cookieHeaderField1 = ["Set-Cookie": cookieStr1]
let cookies1 = HTTPCookie.cookies(withResponseHeaderFields: cookieHeaderField1, for: url!)
let cookieHeaderField2 = ["Set-Cookie": cookieStr2]
let cookies2 = HTTPCookie.cookies(withResponseHeaderFields: cookieHeaderField2, for: url!)
let cookieHeaderField3 = ["Set-Cookie": cookieStr3]
let cookies3 = HTTPCookie.cookies(withResponseHeaderFields: cookieHeaderField3, for: url!)
HTTPCookieStorage.shared.setCookies(cookies1, for: url, mainDocumentURL: url)
HTTPCookieStorage.shared.setCookies(cookies2, for: url, mainDocumentURL: url)
HTTPCookieStorage.shared.setCookies(cookies3, for: url, mainDocumentURL: url)
let cookiesArray = HTTPCookieStorage.shared.cookies!
let values = HTTPCookie.requestHeaderFields(with: cookiesArray)
let cookieArrayOptions = ["AVURLAssetHTTPHeaderFieldsKey": values]
let assets = AVURLAsset(url: url!, options: cookieArrayOptions)
let item = AVPlayerItem(asset: assets)
let player = AVPlayer(playerItem: item)
// 動画プレイヤーの用意
let playerController = AVPlayerViewController()
playerController.player = player
self.present(playerController, animated: true, completion: {
player.play()
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
SetCookiesの部分が冗長的な書き方なのでもうちょっとなんとかしたい