在 iOS App 中使用七牛的存储服务
最近,在做一个需要存储文件的应用,自然就先分析和测试了各种云存储的方案,刚开始用是的是阿里云的OSS,不得不说,他们的SDK开发的确实不错,使用起来很容易,但是,他们没有免费的流量,就在我测试的过程中,就产生了一些小的费用,后来我就在考虑一些有免费流量的存储,自然国内的另一提供存储方案的被我发现了——七牛,他每个月有很多的流量,足够个人使用了。但是,他的移动客户端 SDK 开发的是一个阉割版,只能上传,不能管理和下载等。
官方的文档中有很明确的提示:为了防止申请的AccessKey和AccessSecret在客户端泄露,因为别人反编译自己的App,可能会获得自己的秘钥,所以官方做了阉割。建议服务器端返回。
但是,作为一个个人开发者,不想开发太高级的功能,只是想存储一些资源,在App访问,还要建一个服务器,也太坑了,那么这篇文章就是要通过Swift在iOS中生成token。
创建工程
iOS 基本的创建工程不别说,接着使用Pod导入需要使用的包,有两个:
- QIniu
- JSONKit-NoWarning
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
use_frameworks!
pod 'JSONKit-NoWarning'
pod 'Qiniu'
执行:pod update
后,双击打开项目名称.xcworkspace
。
好了,我们的基础工程已经建立了。
分析需求
七牛的文档写的确实不怎么样,我是研究了好久才从坑中爬出来的。
七牛的 token 有三种,分别是:
- 管理策略 token
- 上传策略 token
- 下载策略 url后面需要带签名
管理策略
管理策略是我这一次需要用到的,我准备将我的Bucket中的资源列举出来。
// 管理 Token
func managerToken(url: NSURL, content: String?, contentType: String) -> String {
// 请求内容
var signingStr = ""
if let path = url.path {
signingStr += path
}
if let query = url.query {
signingStr += "?" + query
}
signingStr += "\n"
if contentType == "application/x-www-form-urlencoded" {
if let data = content {
signingStr += data
}
}
// sign
let token = sign(signingStr)
return token
}
// 上传 Token
func uploadToken(bucket: String, fileName: String?) -> String {
let authInfo = NSMutableDictionary(capacity: 3);
// bucket name
authInfo.setValue(bucket, forKey: "scope")
// time
let oneHourLater = NSDate().timeIntervalSince1970 + 3600
print(NSDate(timeIntervalSince1970: NSTimeInterval(oneHourLater)))
authInfo.setValue(NSNumber(longLong: Int64(oneHourLater)), forKey: "deadline")
let token = signWithData(authInfo.JSONString())
return token
}
// 下载 Url
func downLoadURL(url: String, expires: Int64 = 3600) -> String {
let deadline = Int64(NSDate().timeIntervalSince1970) + expires
var downURL = url + "?" + "e=\(deadline)"
downURL += "&token=" + self.sign(downURL)
return downURL
}
// MARK: 内部方法
// KeyID:HMAC:SIGN
private func signWithData(data: String) -> String {
let encodedData = QNUrlSafeBase64.encodeString(data)
return sign(encodedData) + ":" + encodedData
}
// KeyID:DATA
private func sign(data: String) -> String {
let hmac = self.HMACSHA1(data)
return kAccessKeyID + ":" + hmac
}
// SHA1 编码
private func HMACSHA1(text: String) -> String {
var result: [CUnsignedChar]
if let cKey = kAccessKeySecret.cStringUsingEncoding(NSASCIIStringEncoding),
cData = text.cStringUsingEncoding(NSASCIIStringEncoding)
{
let algo = CCHmacAlgorithm(kCCHmacAlgSHA1)
result = Array(count: Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CCHmac(algo, cKey, cKey.count - 1, cData, cData.count - 1, &result)
} else {
return ""
}
let HMAC = NSData(bytes: result, length: Int(CC_SHA1_DIGEST_LENGTH))
let hash = QNUrlSafeBase64.encodeData(HMAC)
return hash
}
上面就是这一次的所有核心代码。