Skip to content

Commit be17d9b

Browse files
committed
Merge pull request #85 from longbai/phasset
phasset
2 parents 9a1b7a0 + 289fa9e commit be17d9b

File tree

5 files changed

+273
-3
lines changed

5 files changed

+273
-3
lines changed

QiniuSDK.xcodeproj/project.pbxproj

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
22019FE04FB937FAB13FDFFD /* libPods-QiniuSDK iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 389DF9365782A14F70933C3E /* libPods-QiniuSDK iOS.a */; };
1111
5F0FFE6A946BAEFF741BC23E /* libPods-QiniuSDK Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8924D07F6E137C6379C173D4 /* libPods-QiniuSDK Mac.a */; };
1212
7277FD17389341BDCAD29727 /* libPods-QiniuSDK iOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D41D651AEAB89853C760E3A /* libPods-QiniuSDK iOSTests.a */; };
13+
93CEF47E1BDE11FF00750FE8 /* QNPHAssetFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 93CEF47C1BDE11FF00750FE8 /* QNPHAssetFile.h */; settings = {ASSET_TAGS = (); }; };
14+
93CEF47F1BDE11FF00750FE8 /* QNPHAssetFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 93CEF47D1BDE11FF00750FE8 /* QNPHAssetFile.m */; settings = {ASSET_TAGS = (); }; };
15+
93CEF4801BDE11FF00750FE8 /* QNPHAssetFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 93CEF47D1BDE11FF00750FE8 /* QNPHAssetFile.m */; settings = {ASSET_TAGS = (); }; };
1316
DF0A03231B3BABEC00E3778C /* libQiniuSDK Mac.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DF2CDDFF19DAC05500CE01FB /* libQiniuSDK Mac.dylib */; };
1417
DF0A03241B3BAC3900E3778C /* QNFormUploadTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DF3C504619DD7BA6000F548F /* QNFormUploadTest.m */; };
1518
DF0A03251B3BAC5700E3778C /* libQiniuSDK iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF2CDE1A19DAC08400CE01FB /* libQiniuSDK iOS.a */; };
@@ -126,6 +129,8 @@
126129
75127E9F1F2BA68C9D5B463F /* Pods-QiniuSDK iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QiniuSDK iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-QiniuSDK iOS/Pods-QiniuSDK iOS.release.xcconfig"; sourceTree = "<group>"; };
127130
7EFD2A2AD31548D6BD3FD007 /* Pods-QiniuSDK MacTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QiniuSDK MacTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-QiniuSDK MacTests/Pods-QiniuSDK MacTests.release.xcconfig"; sourceTree = "<group>"; };
128131
8924D07F6E137C6379C173D4 /* libPods-QiniuSDK Mac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-QiniuSDK Mac.a"; sourceTree = BUILT_PRODUCTS_DIR; };
132+
93CEF47C1BDE11FF00750FE8 /* QNPHAssetFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QNPHAssetFile.h; sourceTree = "<group>"; };
133+
93CEF47D1BDE11FF00750FE8 /* QNPHAssetFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QNPHAssetFile.m; sourceTree = "<group>"; };
129134
948F5D59B2BD6CACC644FA14 /* Pods-QiniuSDK MacTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QiniuSDK MacTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-QiniuSDK MacTests/Pods-QiniuSDK MacTests.debug.xcconfig"; sourceTree = "<group>"; };
130135
9A0CE9E3B1F13E790C38CB75 /* Pods-QiniuSDK iOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QiniuSDK iOSTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-QiniuSDK iOSTests/Pods-QiniuSDK iOSTests.release.xcconfig"; sourceTree = "<group>"; };
131136
C24CE1990894CD3CA9A17042 /* Pods-QiniuSDK iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QiniuSDK iOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-QiniuSDK iOSTests/Pods-QiniuSDK iOSTests.debug.xcconfig"; sourceTree = "<group>"; };
@@ -340,6 +345,8 @@
340345
DFF126F01B639F3B0005C39C /* QNFile.m */,
341346
DFF126F41B63ABED0005C39C /* QNALAssetFile.h */,
342347
DFF126F51B63ABED0005C39C /* QNALAssetFile.m */,
348+
93CEF47C1BDE11FF00750FE8 /* QNPHAssetFile.h */,
349+
93CEF47D1BDE11FF00750FE8 /* QNPHAssetFile.m */,
343350
DFBF636D1BCCE28200A771D8 /* QNSystem.m */,
344351
DFBF63701BCCE2A600A771D8 /* QNSystem.h */,
345352
);
@@ -416,6 +423,7 @@
416423
DF482FD81B0DA8A2000DAD98 /* QNConfiguration.h in Headers */,
417424
DF609A051A58E39D00AC7297 /* QNFormUpload.h in Headers */,
418425
DFF525371A626A3700D02BA1 /* QNHttpDelegate.h in Headers */,
426+
93CEF47E1BDE11FF00750FE8 /* QNPHAssetFile.h in Headers */,
419427
DF2CDE6019DAC6A400CE01FB /* QNCrc32.h in Headers */,
420428
DFF126F11B639F3B0005C39C /* QNFile.h in Headers */,
421429
DFA9B63B19DF904000A15FD1 /* QNEtag.h in Headers */,
@@ -706,6 +714,7 @@
706714
DF609A061A58E39D00AC7297 /* QNFormUpload.m in Sources */,
707715
DF293C9F19DBC2AE00799011 /* QNUserAgent.m in Sources */,
708716
DFA9B65919E0B53700A15FD1 /* QNFileRecorder.m in Sources */,
717+
93CEF47F1BDE11FF00750FE8 /* QNPHAssetFile.m in Sources */,
709718
DF2CDE6119DAC6A400CE01FB /* QNCrc32.m in Sources */,
710719
DF293CA619DC05B800799011 /* QNHttpManager.m in Sources */,
711720
DF293CAB19DC0E5300799011 /* QNResumeUpload.m in Sources */,
@@ -751,6 +760,7 @@
751760
DF437CD51B2426270099587B /* GTM_Base64.m in Sources */,
752761
DF482FDA1B0DA8A2000DAD98 /* QNConfiguration.m in Sources */,
753762
DF609A081A58E39D00AC7297 /* QNFormUpload.m in Sources */,
763+
93CEF4801BDE11FF00750FE8 /* QNPHAssetFile.m in Sources */,
754764
DF293CA019DBC2AE00799011 /* QNUserAgent.m in Sources */,
755765
DFA9B65A19E0B53700A15FD1 /* QNFileRecorder.m in Sources */,
756766
DF2CDE6219DAC6A400CE01FB /* QNCrc32.m in Sources */,
@@ -819,7 +829,8 @@
819829
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
820830
GCC_WARN_UNUSED_FUNCTION = YES;
821831
GCC_WARN_UNUSED_VARIABLE = YES;
822-
MACOSX_DEPLOYMENT_TARGET = 10.10;
832+
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
833+
MACOSX_DEPLOYMENT_TARGET = 10.9;
823834
MTL_ENABLE_DEBUG_INFO = YES;
824835
ONLY_ACTIVE_ARCH = YES;
825836
SDKROOT = macosx;
@@ -854,7 +865,8 @@
854865
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
855866
GCC_WARN_UNUSED_FUNCTION = YES;
856867
GCC_WARN_UNUSED_VARIABLE = YES;
857-
MACOSX_DEPLOYMENT_TARGET = 10.10;
868+
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
869+
MACOSX_DEPLOYMENT_TARGET = 10.9;
858870
MTL_ENABLE_DEBUG_INFO = NO;
859871
SDKROOT = macosx;
860872
};

QiniuSDK/Common/QNPHAssetFile.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// QNPHAssetFile.h
3+
// Pods
4+
//
5+
// Created by 何舒 on 15/10/21.
6+
//
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
#import "QNFileDelegate.h"
12+
13+
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
14+
@class PHAsset;
15+
@interface QNPHAssetFile : NSObject<QNFileDelegate>
16+
/**
17+
* 打开指定文件
18+
*
19+
* @param path 文件路径
20+
* @param error 输出的错误信息
21+
*
22+
* @return 实例
23+
*/
24+
- (instancetype)init:(PHAsset *)phAsset
25+
error:(NSError *__autoreleasing *)error;
26+
@end
27+
#endif

QiniuSDK/Common/QNPHAssetFile.m

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
//
2+
// QNPHAssetFile.m
3+
// Pods
4+
//
5+
// Created by 何舒 on 15/10/21.
6+
//
7+
//
8+
9+
#import "QNPHAssetFile.h"
10+
11+
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
12+
#import <Photos/Photos.h>
13+
14+
enum {
15+
kAMASSETMETADATA_PENDINGREADS = 1,
16+
kAMASSETMETADATA_ALLFINISHED = 0
17+
};
18+
19+
#import "QNResponseInfo.h"
20+
21+
@interface QNPHAssetFile ()
22+
{
23+
BOOL _hasGotInfo;
24+
}
25+
26+
@property (nonatomic) PHAsset * phAsset;
27+
28+
@property (readonly) int64_t fileSize;
29+
30+
@property (readonly) int64_t fileModifyTime;
31+
32+
@property (nonatomic, strong) NSData *assetData;
33+
34+
@property (nonatomic, strong) NSURL *assetURL;
35+
36+
@end
37+
38+
@implementation QNPHAssetFile
39+
40+
- (instancetype)init:(PHAsset *)phAsset error:(NSError *__autoreleasing *)error
41+
{
42+
if (self = [super init]) {
43+
NSDate *createTime = phAsset.creationDate;
44+
int64_t t = 0;
45+
if (createTime != nil) {
46+
t = [createTime timeIntervalSince1970];
47+
}
48+
_fileModifyTime = t;
49+
_phAsset = phAsset;
50+
[self getInfo];
51+
52+
}
53+
return self;
54+
}
55+
56+
- (NSData *)read:(long)offset size:(long)size
57+
{
58+
NSRange subRange = NSMakeRange(offset, size);
59+
if (!self.assetData) {
60+
self.assetData = [self fetchDataFromAsset:self.phAsset];
61+
}
62+
NSData *subData = [self.assetData subdataWithRange:subRange];
63+
64+
return subData;
65+
}
66+
67+
- (NSData *)readAll {
68+
return [self read:0 size:(long)_fileSize];
69+
}
70+
71+
- (void)close {
72+
}
73+
74+
-(NSString *)path {
75+
return self.assetURL.path;
76+
}
77+
78+
- (int64_t)modifyTime {
79+
return _fileModifyTime;
80+
}
81+
82+
- (int64_t)size {
83+
return _fileSize;
84+
}
85+
86+
- (void)getInfo
87+
{
88+
if (!_hasGotInfo) {
89+
_hasGotInfo = YES;
90+
91+
if (PHAssetMediaTypeImage == self.phAsset.mediaType) {
92+
PHImageRequestOptions *request = [PHImageRequestOptions new];
93+
request.version = PHImageRequestOptionsVersionCurrent;
94+
request.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
95+
request.resizeMode = PHImageRequestOptionsResizeModeNone;
96+
request.synchronous = YES;
97+
98+
[[PHImageManager defaultManager] requestImageDataForAsset:self.phAsset
99+
options:request
100+
resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
101+
_fileSize = imageData.length;
102+
_assetURL = [NSURL URLWithString:self.phAsset.localIdentifier];
103+
}
104+
];
105+
}
106+
else if (PHAssetMediaTypeVideo == self.phAsset.mediaType) {
107+
PHVideoRequestOptions *request = [PHVideoRequestOptions new];
108+
request.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
109+
request.version = PHVideoRequestOptionsVersionCurrent;
110+
111+
NSConditionLock* assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS];
112+
[[PHImageManager defaultManager] requestPlayerItemForVideo:self.phAsset options:request resultHandler:^(AVPlayerItem *playerItem, NSDictionary *info) {
113+
AVURLAsset *urlAsset = (AVURLAsset *)playerItem.asset;
114+
NSNumber *fileSize = nil;
115+
[urlAsset.URL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:nil];
116+
_fileSize = [fileSize unsignedLongLongValue];
117+
_assetURL = urlAsset.URL;
118+
119+
[assetReadLock lock];
120+
[assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED];
121+
}];
122+
[assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED];
123+
[assetReadLock unlock];
124+
assetReadLock = nil;
125+
}
126+
}
127+
128+
}
129+
130+
- (NSData *)fetchDataFromAsset:(PHAsset *)asset
131+
{
132+
__block NSData *tmpData = [NSData data];
133+
134+
// Image
135+
if (asset.mediaType == PHAssetMediaTypeImage) {
136+
PHImageRequestOptions *request = [PHImageRequestOptions new];
137+
request.version = PHImageRequestOptionsVersionCurrent;
138+
request.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
139+
request.resizeMode = PHImageRequestOptionsResizeModeNone;
140+
request.synchronous = YES;
141+
142+
[[PHImageManager defaultManager] requestImageDataForAsset:asset
143+
options:request
144+
resultHandler:
145+
^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
146+
tmpData = [NSData dataWithData:imageData];
147+
}];
148+
}
149+
// Video
150+
else {
151+
152+
PHVideoRequestOptions *request = [PHVideoRequestOptions new];
153+
request.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
154+
request.version = PHVideoRequestOptionsVersionCurrent;
155+
156+
NSConditionLock *assetReadLock = [[NSConditionLock alloc] initWithCondition:kAMASSETMETADATA_PENDINGREADS];
157+
158+
159+
[[PHImageManager defaultManager] requestAVAssetForVideo:asset
160+
options:request
161+
resultHandler:
162+
^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
163+
AVURLAsset *urlAsset = (AVURLAsset *)asset;
164+
NSData *videoData = [NSData dataWithContentsOfURL:urlAsset.URL];
165+
tmpData = [NSData dataWithData:videoData];
166+
167+
[assetReadLock lock];
168+
[assetReadLock unlockWithCondition:kAMASSETMETADATA_ALLFINISHED];
169+
}];
170+
171+
[assetReadLock lockWhenCondition:kAMASSETMETADATA_ALLFINISHED];
172+
[assetReadLock unlock];
173+
assetReadLock = nil;
174+
}
175+
176+
return tmpData;
177+
}
178+
179+
@end
180+
#endif

QiniuSDK/Storage/QNUploadManager.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010

1111
#import "QNRecorderDelegate.h"
1212

13+
1314
@class QNResponseInfo;
1415
@class QNUploadOption;
1516
@class QNConfiguration;
1617
@class ALAsset;
18+
@class PHAsset;
19+
20+
1721
/**
1822
* 上传完成后的回调函数
1923
*
@@ -119,4 +123,19 @@ typedef void (^QNUpCompletionHandler)(QNResponseInfo *info, NSString *key, NSDic
119123
complete:(QNUpCompletionHandler)completionHandler
120124
option:(QNUploadOption *)option;
121125

126+
/**
127+
* 上传PHAsset文件(IOS8 andLater)
128+
*
129+
* @param asset PHAsset文件
130+
* @param key 上传到云存储的key,为nil时表示是由七牛生成
131+
* @param token 上传需要的token, 由服务器生成
132+
* @param completionHandler 上传完成后的回调函数
133+
* @param option 上传时传入的可选参数
134+
*/
135+
- (void) putPHAsset:(PHAsset *)asset
136+
key:(NSString *)key
137+
token:(NSString *)token
138+
complete:(QNUpCompletionHandler)completionHandler
139+
option:(QNUploadOption *)option;
140+
122141
@end

QiniuSDK/Storage/QNUploadManager.m

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,17 @@
1313
#import <UIKit/UIKit.h>
1414
#import "QNALAssetFile.h"
1515
#import <AssetsLibrary/AssetsLibrary.h>
16+
17+
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
18+
#import "QNPHAssetFile.h"
19+
#import <Photos/Photos.h>
20+
#endif
21+
1622
#else
1723
#import <CoreServices/CoreServices.h>
1824
#endif
1925

26+
2027
#import "QNConfiguration.h"
2128
#import "QNHttpManager.h"
2229
#import "QNSessionManager.h"
@@ -63,7 +70,7 @@ - (instancetype)initWithConfiguration:(QNConfiguration *)config {
6370
}
6471
_config = config;
6572
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
66-
if (hasNSURLSession()) {
73+
if (hasNSURLSession()) {
6774
_httpManager = [[QNSessionManager alloc] initWithProxy:config.proxy timeout:config.timeoutInterval urlConverter:config.converter dns:config.dns];
6875
}
6976
else {
@@ -255,4 +262,29 @@ - (void) putALAsset:(ALAsset *)asset
255262
#endif
256263
}
257264

265+
- (void) putPHAsset:(PHAsset *)asset
266+
key:(NSString *)key
267+
token:(NSString *)token
268+
complete:(QNUpCompletionHandler)completionHandler
269+
option:(QNUploadOption *)option {
270+
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
271+
if ([QNUploadManager checkAndNotifyError:key token:token input:asset complete:completionHandler]) {
272+
return;
273+
}
274+
275+
@autoreleasepool {
276+
NSError *error = nil;
277+
__block QNPHAssetFile *file = [[QNPHAssetFile alloc] init:asset error:&error];
278+
if (error) {
279+
QNAsyncRunInMain( ^{
280+
QNResponseInfo *info = [QNResponseInfo responseInfoWithFileError:error];
281+
completionHandler(info, key, nil);
282+
});
283+
return;
284+
}
285+
[self putFileInternal:file key:key token:token complete:completionHandler option:option];
286+
}
287+
#endif
288+
}
289+
258290
@end

0 commit comments

Comments
 (0)