Skip to content

Commit 2acbde4

Browse files
authored
🐛 [iOS] Fix the behavior of obtaining Live Photos (#1140)
1 parent 667f5a1 commit 2acbde4

21 files changed

+121
-122
lines changed

CHANGELOG.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,23 @@ that can be found in the LICENSE file. -->
66

77
To know more about breaking changes, see the [Migration Guide][].
88

9+
## 3.2.0
10+
11+
### Improvements
12+
13+
* Restores `containsLivePhotos` to `true` by default and deprecates it.
14+
* Use the main resource's filename for title by default on iOS.
15+
16+
### Fixes
17+
18+
* Fix obtaining the correct resource from various types of resources on iOS.
19+
* Fix `isLocallyAvailable` for edited assets on iOS.
20+
921
## 3.1.1
1022

1123
### Improvements
1224

13-
* Update plugin structure for OpenHarmony
25+
* Update plugin structure for OpenHarmony.
1426

1527
## 3.1.0
1628

analysis_options.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ analyzer:
88
avoid_void_async: error
99
camel_case_types: error
1010
constant_identifier_names: error
11+
deprecated_member_use_from_same_package: ignore
1112
non_constant_identifier_names: error
1213
prefer_single_quotes: warning
1314
require_trailing_commas: warning

example/ios/Flutter/AppFrameworkInfo.plist

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
<key>CFBundleVersion</key>
2222
<string>1.0</string>
2323
<key>MinimumOSVersion</key>
24-
<string>11.0</string>
24+
<string>12.0</string>
2525
</dict>
2626
</plist>

example/ios/Podfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Uncomment this line to define a global platform for your project
2-
platform :ios, '11.0'
2+
platform :ios, '12.0'
33

44
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
55
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

example/ios/Runner.xcodeproj/project.pbxproj

+7-7
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155
97C146E61CF9000F007C117D /* Project object */ = {
156156
isa = PBXProject;
157157
attributes = {
158-
LastUpgradeCheck = 1430;
158+
LastUpgradeCheck = 1510;
159159
ORGANIZATIONNAME = "";
160160
TargetAttributes = {
161161
97C146ED1CF9000F007C117D = {
@@ -342,7 +342,7 @@
342342
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
343343
GCC_WARN_UNUSED_FUNCTION = YES;
344344
GCC_WARN_UNUSED_VARIABLE = YES;
345-
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
345+
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
346346
MTL_ENABLE_DEBUG_INFO = NO;
347347
SDKROOT = iphoneos;
348348
SUPPORTED_PLATFORMS = iphoneos;
@@ -361,7 +361,7 @@
361361
DEVELOPMENT_TEAM = S5GU4EMC47;
362362
ENABLE_BITCODE = NO;
363363
INFOPLIST_FILE = Runner/Info.plist;
364-
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
364+
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
365365
LD_RUNPATH_SEARCH_PATHS = (
366366
"$(inherited)",
367367
"@executable_path/Frameworks",
@@ -421,7 +421,7 @@
421421
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
422422
GCC_WARN_UNUSED_FUNCTION = YES;
423423
GCC_WARN_UNUSED_VARIABLE = YES;
424-
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
424+
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
425425
MTL_ENABLE_DEBUG_INFO = YES;
426426
ONLY_ACTIVE_ARCH = YES;
427427
SDKROOT = iphoneos;
@@ -470,7 +470,7 @@
470470
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
471471
GCC_WARN_UNUSED_FUNCTION = YES;
472472
GCC_WARN_UNUSED_VARIABLE = YES;
473-
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
473+
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
474474
MTL_ENABLE_DEBUG_INFO = NO;
475475
SDKROOT = iphoneos;
476476
SUPPORTED_PLATFORMS = iphoneos;
@@ -491,7 +491,7 @@
491491
DEVELOPMENT_TEAM = S5GU4EMC47;
492492
ENABLE_BITCODE = NO;
493493
INFOPLIST_FILE = Runner/Info.plist;
494-
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
494+
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
495495
LD_RUNPATH_SEARCH_PATHS = (
496496
"$(inherited)",
497497
"@executable_path/Frameworks",
@@ -515,7 +515,7 @@
515515
DEVELOPMENT_TEAM = S5GU4EMC47;
516516
ENABLE_BITCODE = NO;
517517
INFOPLIST_FILE = Runner/Info.plist;
518-
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
518+
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
519519
LD_RUNPATH_SEARCH_PATHS = (
520520
"$(inherited)",
521521
"@executable_path/Frameworks",

example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1430"
3+
LastUpgradeVersion = "1510"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

example/lib/main.dart

+7-7
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,6 @@ class _SimpleExamplePage extends StatefulWidget {
6868
}
6969

7070
class _SimpleExamplePageState extends State<_SimpleExamplePage> {
71-
/// Customize your own filter options.
72-
final FilterOptionGroup _filterOptionGroup = FilterOptionGroup(
73-
imageOption: const FilterOption(
74-
sizeConstraint: SizeConstraint(ignoreSize: true),
75-
),
76-
);
7771
final int _sizePerPage = 50;
7872

7973
AssetPathEntity? _path;
@@ -102,10 +96,16 @@ class _SimpleExamplePageState extends State<_SimpleExamplePage> {
10296
showToast('Permission is not accessible.');
10397
return;
10498
}
99+
// Customize your own filter options.
100+
final PMFilter filter = FilterOptionGroup(
101+
imageOption: const FilterOption(
102+
sizeConstraint: SizeConstraint(ignoreSize: true),
103+
),
104+
);
105105
// Obtain assets using the path entity.
106106
final List<AssetPathEntity> paths = await PhotoManager.getAssetPathList(
107107
onlyAll: true,
108-
filterOption: _filterOptionGroup,
108+
filterOption: filter,
109109
);
110110
if (!mounted) {
111111
return;

example/lib/model/photo_provider.dart

+1
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ class PhotoProvider extends ChangeNotifier {
215215
..setOption(AssetType.audio, option)
216216
..createTimeCond = createDtCond
217217
..containsPathModified = _containsPathModified
218+
// ignore: deprecated_member_use
218219
..containsLivePhotos = _containsLivePhotos
219220
..onlyLivePhotos = onlyLivePhotos;
220221
}

example/lib/page/developer/issues_page/issue_988.dart

+1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class __DeleteAssetImageListState extends State<_DeleteAssetImageList> {
165165
right: 0,
166166
top: 0,
167167
child: Checkbox(
168+
// ignore: deprecated_member_use
168169
overlayColor: MaterialStateProperty.all(Colors.white),
169170
value: checked.contains(asset),
170171
onChanged: (bool? value) {

example/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: photo_manager_example
22
description: Demonstrates how to use the photo_manager plugin.
3-
version: 3.1.0+26
3+
version: 3.2.0+27
44
publish_to: none
55

66
environment:

ios/Classes/core/PHAsset+PM_COMMON.h

+2-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@ NS_ASSUME_NONNULL_BEGIN
2727
@return The MIME type of this asset if available, otherwise `nil`.
2828
*/
2929
- (nullable NSString*)mimeType;
30-
- (BOOL)isAdjust;
31-
- (PHAssetResource *)getAdjustResource;
32-
- (PHAssetResource *)getUntouchedResource;
33-
- (void)requestAdjustedData:(void (^)(NSData *_Nullable result))block;
30+
- (PHAssetResource *)getCurrentResource;
31+
- (void)requestCurrentResourceData:(void (^)(NSData *_Nullable result))block;
3432
- (PHAssetResource *)getLivePhotosResource;
3533

3634
@end

ios/Classes/core/PHAsset+PM_COMMON.m

+48-48
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55

66
#import "PHAsset+PM_COMMON.h"
7+
#import "PHAssetResource+PM_COMMON.h"
78
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
89
#import <MobileCoreServices/MobileCoreServices.h>
910
#else
@@ -64,11 +65,12 @@ - (NSString *)title {
6465

6566
- (NSString *)originalFilenameWithSubtype:(int)subtype {
6667
if (@available(iOS 9.1, *)) {
67-
if ([self isLivePhoto] && subtype == PHAssetMediaSubtypePhotoLive) {
68+
BOOL isLivePhotoSubtype = (subtype & PHAssetMediaSubtypePhotoLive) == PHAssetMediaSubtypePhotoLive;
69+
if ([self isLivePhoto] && isLivePhotoSubtype) {
6870
return [self getLivePhotosResource].originalFilename;
6971
}
7072
}
71-
PHAssetResource *resource = [self getUntouchedResource];
73+
PHAssetResource *resource = [self getRawResource];
7274
if (resource) {
7375
return resource.originalFilename;
7476
}
@@ -123,63 +125,64 @@ - (BOOL)videoIsAdjust:(NSArray<PHAssetResource *> *)resources {
123125
return NO;
124126
}
125127

126-
- (PHAssetResource *)getUntouchedResource {
128+
- (PHAssetResource *)getRawResource {
127129
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:self];
128-
if (resources.count == 0) {
129-
return nil;
130-
}
131-
132-
if (resources.count == 1) {
133-
return resources[0];
134-
}
135-
136130
for (PHAssetResource *res in resources) {
137-
if (self.mediaType == PHAssetMediaTypeImage
138-
&& res.type == PHAssetResourceTypePhoto) {
131+
if (self.isImage && res.isImage && res.type == PHAssetResourceTypePhoto) {
139132
return res;
140133
}
141-
142-
if (self.mediaType == PHAssetMediaTypeVideo
143-
&& res.type == PHAssetResourceTypeVideo) {
134+
if (self.isVideo && res.isVideo && res.type == PHAssetResourceTypeVideo) {
135+
return res;
136+
}
137+
if (self.isAudio && res.isAudio && res.type == PHAssetResourceTypeAudio) {
144138
return res;
145139
}
146140
}
147-
148141
return nil;
149142
}
150143

151-
- (PHAssetResource *)getAdjustResource {
144+
- (PHAssetResource *)getCurrentResource {
152145
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:self];
153-
if (resources.count == 0) {
146+
NSMutableArray<PHAssetResource *> *filtered = [NSMutableArray array];
147+
for (PHAssetResource *res in resources) {
148+
if (!res.isValid) {
149+
continue;
150+
}
151+
BOOL isAllowedType = NO;
152+
if (self.isImage && res.isImage) {
153+
isAllowedType = res.type == PHAssetResourceTypePhoto ||
154+
res.type == PHAssetResourceTypeAlternatePhoto ||
155+
res.type == PHAssetResourceTypeFullSizePhoto;
156+
} else if (self.isVideo && res.isVideo) {
157+
isAllowedType = res.type == PHAssetResourceTypeVideo ||
158+
res.type == PHAssetResourceTypeFullSizeVideo ||
159+
res.type == PHAssetResourceTypeFullSizePairedVideo;
160+
} else if (self.isAudio && res.isAudio) {
161+
isAllowedType = res.type == PHAssetResourceTypeAudio;
162+
}
163+
if (isAllowedType) {
164+
[filtered addObject:res];
165+
}
166+
}
167+
if (filtered.count == 0) {
154168
return nil;
155169
}
156170

157-
if (resources.count == 1) {
171+
if (filtered.count == 1) {
158172
return resources[0];
159173
}
160174

161-
if (![self isAdjust]) {
162-
for (PHAssetResource *res in resources) {
163-
if (self.mediaType == PHAssetMediaTypeImage
164-
&& res.type == PHAssetResourceTypePhoto) {
165-
return res;
166-
}
167-
168-
if (self.mediaType == PHAssetMediaTypeVideo
169-
&& res.type == PHAssetResourceTypeVideo) {
170-
return res;
171-
}
175+
for (PHAssetResource *res in filtered) {
176+
BOOL isCurrent = [[res valueForKey:@"isCurrent"] boolValue];
177+
if (isCurrent) {
178+
return res;
172179
}
173-
174-
return nil;
175180
}
176-
177-
for (PHAssetResource *res in resources) {
181+
for (PHAssetResource *res in filtered) {
178182
if (self.mediaType == PHAssetMediaTypeImage &&
179183
res.type == PHAssetResourceTypeFullSizePhoto) {
180184
return res;
181185
}
182-
183186
if (self.mediaType == PHAssetMediaTypeVideo &&
184187
res.type == PHAssetResourceTypeFullSizeVideo) {
185188
return res;
@@ -188,8 +191,8 @@ - (PHAssetResource *)getAdjustResource {
188191
return nil;
189192
}
190193

191-
- (void)requestAdjustedData:(void (^)(NSData *_Nullable))block {
192-
PHAssetResource *res = [self getAdjustResource];
194+
- (void)requestCurrentResourceData:(void (^)(NSData *_Nullable))block {
195+
PHAssetResource *res = [self getCurrentResource];
193196

194197
PHAssetResourceManager *manager = PHAssetResourceManager.defaultManager;
195198
PHAssetResourceRequestOptions *opt = [PHAssetResourceRequestOptions new];
@@ -228,19 +231,16 @@ - (PHAssetResource *)getLivePhotosResource {
228231

229232
if (@available(iOS 9.1, *)) {
230233
if (resources.lastObject && resources.lastObject.type == PHAssetResourceTypePairedVideo) {
231-
resource = resources.lastObject;
232-
}
233-
if (!resource) {
234-
for (PHAssetResource *r in resources) {
235-
// Iterate to find the paired video.
236-
if (r.type == PHAssetResourceTypePairedVideo) {
237-
resource = r;
238-
break;
239-
}
234+
return resources.lastObject;
235+
}
236+
for (PHAssetResource *r in resources) {
237+
// Iterate to find the paired video.
238+
if (r.type == PHAssetResourceTypePairedVideo) {
239+
return r;
240240
}
241241
}
242242
}
243-
return resource;
243+
return nil;
244244
}
245245

246246
@end

ios/Classes/core/PHAssetResource+PM_COMMON.h

+1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@
1111
- (bool)isVideo;
1212
- (bool)isAudio;
1313
- (bool)isImageOrVideo;
14+
- (bool)isValid;
1415

1516
@end

ios/Classes/core/PHAssetResource+PM_COMMON.m

+8
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,12 @@ - (bool)isImageOrVideo{
3737
return [self isVideo] || [self isImage];
3838
}
3939

40+
- (bool)isValid {
41+
bool isResource = self.type != PHAssetResourceTypeAdjustmentData;
42+
if (@available(iOS 17.0, *)) {
43+
isResource = isResource && self.type != PHAssetResourceTypePhotoProxy;
44+
}
45+
return isResource;
46+
}
47+
4048
@end

ios/Classes/core/PMFilterOption.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,4 @@ typedef struct PMDurationConstraint {
6868

6969
@interface PMCustomFilterOption : NSObject <PMBaseFilter>
7070
@property (nonatomic, strong) NSDictionary *params;
71-
@end
71+
@end

ios/Classes/core/PMFilterOption.m

-15
Original file line numberDiff line numberDiff line change
@@ -113,21 +113,6 @@ - (PHFetchOptions *)getFetchOptions:(int)type {
113113
[cond appendString:durationCond];
114114
[args addObjectsFromArray:durationArgs];
115115

116-
if (@available(iOS 9.1, *)) {
117-
if (!containsImage && optionGroup.containsLivePhotos) {
118-
[cond appendString:@" )"];
119-
[cond appendString:@" OR "];
120-
[cond appendString:@"( "];
121-
[cond appendString:@"mediaType == %d"];
122-
[args addObject:@(PHAssetMediaTypeImage)];
123-
[cond appendString:@" AND "];
124-
[cond appendString:[NSString
125-
stringWithFormat:@"( mediaSubtype & %lu ) == 8",
126-
(unsigned long) PHAssetMediaSubtypePhotoLive]
127-
];
128-
}
129-
}
130-
131116
[cond appendString:@" ) "];
132117
}
133118

0 commit comments

Comments
 (0)