From 5173dd2114c7f7c180a23911f2a94855fd350813 Mon Sep 17 00:00:00 2001 From: Jidong Chen <jidongchen93@gmail.com> Date: Tue, 11 Jun 2019 20:12:02 +0800 Subject: [PATCH] update --- ios/Classes/1.0/FLBFactory.m | 1 + ios/Classes/1.0/FLBFlutterEngine.m | 93 -------- ios/Classes/1.0/FLBFlutterEngineOld.m | 4 - ios/Classes/1.0/FLBFlutterProvider.h | 4 +- ios/Classes/1.0/FLBViewProviderFactory.m | 8 - ios/Classes/1.0/Support/Cache/FLBStackCache.h | 72 ++++++ ios/Classes/1.0/Support/Cache/FLBStackCache.m | 210 ++++++++++++++++++ .../Cache/FLBStackCacheObjectImg.h} | 14 +- .../Support/Cache/FLBStackCacheObjectImg.m | 116 ++++++++++ .../1.0/Support/Memory/FLBMemoryInspector.h | 47 ++++ .../1.0/Support/Memory/FLBMemoryInspector.mm | 157 +++++++++++++ 11 files changed, 611 insertions(+), 115 deletions(-) delete mode 100755 ios/Classes/1.0/FLBFlutterEngine.m create mode 100755 ios/Classes/1.0/Support/Cache/FLBStackCache.h create mode 100755 ios/Classes/1.0/Support/Cache/FLBStackCache.m rename ios/Classes/1.0/{FLBFlutterEngine.h => Support/Cache/FLBStackCacheObjectImg.h} (85%) create mode 100755 ios/Classes/1.0/Support/Cache/FLBStackCacheObjectImg.m create mode 100755 ios/Classes/1.0/Support/Memory/FLBMemoryInspector.h create mode 100755 ios/Classes/1.0/Support/Memory/FLBMemoryInspector.mm diff --git a/ios/Classes/1.0/FLBFactory.m b/ios/Classes/1.0/FLBFactory.m index dcdf2f0..c7fb089 100644 --- a/ios/Classes/1.0/FLBFactory.m +++ b/ios/Classes/1.0/FLBFactory.m @@ -38,4 +38,5 @@ return FLBFlutterViewContainer.new; } + @end diff --git a/ios/Classes/1.0/FLBFlutterEngine.m b/ios/Classes/1.0/FLBFlutterEngine.m deleted file mode 100755 index 14ed54a..0000000 --- a/ios/Classes/1.0/FLBFlutterEngine.m +++ /dev/null @@ -1,93 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Alibaba Group - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#import "FLBFlutterEngine.h" -#import <Flutter/Flutter.h> -#import "FLBFlutterViewControllerAdaptor.h" - -#if RELEASE_1_0 - -@interface FLBFlutterEngine() -@property (nonatomic,strong) FLBFlutterViewControllerAdaptor *viewController; -@property (nonatomic,strong) FlutterEngine *engine; -@end - -@implementation FLBFlutterEngine - -- (instancetype)init -{ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - - if (self = [super init]) { - _engine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil]; - [_engine runWithEntrypoint:nil]; - _viewController = [[FLBFlutterViewControllerAdaptor alloc] initWithEngine:_engine - nibName:nil - bundle:nil]; - [_viewController view]; - Class clazz = NSClassFromString(@"GeneratedPluginRegistrant"); - if (clazz) { - if ([clazz respondsToSelector:NSSelectorFromString(@"registerWithRegistry:")]) { - [clazz performSelector:NSSelectorFromString(@"registerWithRegistry:") - withObject:_viewController]; - } - } - } - - return self; -#pragma clang diagnostic pop -} - -- (FlutterViewController *)viewController -{ - return _viewController; -} - -- (void)pause -{ - //TODO: [[_engine.get() lifecycleChannel] sendMessage:@"AppLifecycleState.paused"]; - [self.viewController boost_viewWillDisappear:NO]; - [self.viewController boost_viewDidDisappear:NO]; -} - -- (void)resume -{ - //TODO: [[_engine.get() lifecycleChannel] sendMessage:@"AppLifecycleState.resumed"]; - [self.viewController boost_viewWillAppear:NO]; - [self.viewController boost_viewDidAppear:NO]; -} - -- (void)inactive -{ - [[_engine lifecycleChannel] sendMessage:@"AppLifecycleState.inactive"]; -} - -- (void)setAccessibilityEnable:(BOOL)enable -{ - self.viewController.accessibilityEnable = enable; -} -@end - -#endif diff --git a/ios/Classes/1.0/FLBFlutterEngineOld.m b/ios/Classes/1.0/FLBFlutterEngineOld.m index 3e596d2..6ee57cc 100755 --- a/ios/Classes/1.0/FLBFlutterEngineOld.m +++ b/ios/Classes/1.0/FLBFlutterEngineOld.m @@ -100,9 +100,5 @@ [self.viewController sendOnChannel:channel message:data]; } -- (void)setAccessibilityEnable:(BOOL)enable -{ - self.viewController.accessibilityEnable = enable; -} @end diff --git a/ios/Classes/1.0/FLBFlutterProvider.h b/ios/Classes/1.0/FLBFlutterProvider.h index a514c49..bb50d05 100755 --- a/ios/Classes/1.0/FLBFlutterProvider.h +++ b/ios/Classes/1.0/FLBFlutterProvider.h @@ -34,9 +34,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol FLBFlutterProvider <NSObject> @required -- (FlutterEngine *)engine; -- (void)atacheToViewController:(FlutterViewController *)vc; -- (void)detach; + - (void)pause; - (void)resume; - (void)inactive; diff --git a/ios/Classes/1.0/FLBViewProviderFactory.m b/ios/Classes/1.0/FLBViewProviderFactory.m index 0bd7d26..20c4b67 100755 --- a/ios/Classes/1.0/FLBViewProviderFactory.m +++ b/ios/Classes/1.0/FLBViewProviderFactory.m @@ -32,20 +32,12 @@ - (id<FLBFlutterViewProvider>)createViewProviderWithPlatform:(id<FLBPlatform>)platform { -#if RELEASE_1_0 - return [FLBFlutterEngine new]; -#else return [[FLBFlutterEngineOld alloc] initWithPlatform:platform]; -#endif } - (id<FLBFlutterViewProvider>)createViewProvider { -#if RELEASE_1_0 - return [FLBFlutterEngine new]; -#else return [FLBFlutterEngineOld new]; -#endif } @end diff --git a/ios/Classes/1.0/Support/Cache/FLBStackCache.h b/ios/Classes/1.0/Support/Cache/FLBStackCache.h new file mode 100755 index 0000000..75c067c --- /dev/null +++ b/ios/Classes/1.0/Support/Cache/FLBStackCache.h @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Alibaba Group + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import <Foundation/Foundation.h> + +@class FLBStackCache; + +@protocol FLBStackCacheObject<NSObject> + +@required +@property (nonatomic,copy) NSString *key; + +- (BOOL)writeToFileWithKey:(NSString *)key + queue:(dispatch_queue_t)queue + cache:(FLBStackCache *)cache + completion:(void (^)(NSError *err,NSString *path))completion; + ++ (BOOL)loadFromFileWithKey:(NSString *)key + queue:(dispatch_queue_t)queue + cache:(FLBStackCache *)cache + completion:(void (^)(NSError *err ,id<FLBStackCacheObject>))completion; + +- (BOOL)removeCachedFileWithKey:(NSString *)key + queue:(dispatch_queue_t)queue + cache:(FLBStackCache *)cache + completion:(void (^)(NSError *, NSString *))completion; + + +@end + + +@interface FLBStackCache : NSObject ++ (instancetype)sharedInstance; + +/** + * Num of objects allowed in memory. + * Default value is set to 2. + */ +@property (nonatomic,assign) NSUInteger inMemoryCount; + +#pragma mark - basic operations. +- (void)pushObject:(id<FLBStackCacheObject>)obj key:(NSString *)key; +- (id<FLBStackCacheObject>)remove:(NSString *)key; +- (void)invalidate:(NSString *)key; +- (BOOL)empty; +- (void)clear; +- (id<FLBStackCacheObject>)objectForKey:(NSString *)key; + +#pragma mark - Disk thing. +- (NSString *)cacheDir; +@end diff --git a/ios/Classes/1.0/Support/Cache/FLBStackCache.m b/ios/Classes/1.0/Support/Cache/FLBStackCache.m new file mode 100755 index 0000000..3a153d5 --- /dev/null +++ b/ios/Classes/1.0/Support/Cache/FLBStackCache.m @@ -0,0 +1,210 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Alibaba Group + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import "FLBStackCache.h" + +@interface FLBStackCache() + +@property (nonatomic,strong) NSMutableArray *keyStack; +@property (nonatomic,strong) NSMutableDictionary *typesMap; +@property (nonatomic,strong) NSMutableDictionary *inMemoryObjectsMap; +@property (nonatomic,strong) NSMutableDictionary *loadinMap; +@property (nonatomic,strong) dispatch_queue_t queueIO; +@end + +@implementation FLBStackCache + ++ (instancetype)sharedInstance +{ + static id sInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sInstance = [self.class new]; + }); + + return sInstance; +} + +- (BOOL)empty +{ + return _keyStack.count<=0; +} + +- (void)clear +{ + [self.keyStack removeAllObjects]; + [self.inMemoryObjectsMap removeAllObjects]; + [self.typesMap removeAllObjects]; + NSError *err = nil; + [[NSFileManager defaultManager] removeItemAtPath:self.cacheDir error:&err]; + if (err) { + NSLog(@"fail to remove cache dir %@",err); + } +} + + +- (instancetype)init +{ + if (self = [super init]) { + _keyStack = [NSMutableArray new]; + _inMemoryObjectsMap = [NSMutableDictionary new]; + _loadinMap = [NSMutableDictionary new]; + _typesMap = [NSMutableDictionary new]; + _queueIO = dispatch_queue_create("Stack cache working queue", NULL); + } + _inMemoryCount = 2; + return self; +} + + - (void)pushObject:(id<FLBStackCacheObject>)obj + key:(NSString *)key +{ + if (!obj || key.length <= 0) { + return; + } + + if(![_keyStack containsObject:key]){ + [_keyStack addObject:key]; + }else{ + //return; + } + + obj.key = key; + _typesMap[key] = obj.class; + _inMemoryObjectsMap[key] = obj; + + for(NSUInteger i = _keyStack.count - _inMemoryObjectsMap.count ; + i < _keyStack.count && _inMemoryObjectsMap.count > _inMemoryCount; + i++){ + + NSString *keyToSave = _keyStack[i]; + if(_inMemoryObjectsMap[keyToSave]){ + id<FLBStackCacheObject> ob = _inMemoryObjectsMap[keyToSave]; + [_inMemoryObjectsMap removeObjectForKey:keyToSave]; + [ob writeToFileWithKey:keyToSave + queue:_queueIO + cache:self + completion:^(NSError *err, NSString *path) { + if (err) { + NSLog(@"Caching object to file failed!"); + } + }]; + } + } +} + +- (id<FLBStackCacheObject>)objectForKey:(NSString *)key +{ + return _inMemoryObjectsMap[key]; +} + +- (id<FLBStackCacheObject>)remove:(NSString *)key +{ + if([self empty]) return nil; + + if(![_keyStack containsObject:key]) return nil; + + id ob = _inMemoryObjectsMap[key]; + + [_keyStack removeObject:key]; + [_inMemoryObjectsMap removeObjectForKey:key]; + [_typesMap removeObjectForKey:key]; + + [self preloadIfNeeded]; + + return ob; +} + +- (void)invalidate:(NSString *)key +{ + if(!key || [self empty]) return; + + if(![_keyStack containsObject:key]) return; + + id<FLBStackCacheObject> ob = _inMemoryObjectsMap[key]; + [ob removeCachedFileWithKey:key + queue:_queueIO + cache:self + completion:^(NSError *err, NSString *k) { + }]; + [_inMemoryObjectsMap removeObjectForKey:key]; + + [self preloadIfNeeded]; +} + +- (void)preloadIfNeeded +{ + for(NSString *key in self.keyStack.reverseObjectEnumerator){ + Class typeClass = _typesMap[key]; + id cache = _inMemoryObjectsMap[key]; + if(typeClass && !cache && [typeClass conformsToProtocol: @protocol(FLBStackCacheObject)]){ + _loadinMap[key] = @(YES); + [typeClass loadFromFileWithKey:key + queue:_queueIO + cache:self + completion:^(NSError *err ,id<FLBStackCacheObject> ob){ + [self.loadinMap removeObjectForKey:key]; + if (ob && !err) { + if(self.typesMap[key]){ + self.inMemoryObjectsMap[key] = ob; + } + }else{ + NSLog(@"preload object from file failed!"); + } + }]; + } + + if(_inMemoryObjectsMap.count + _loadinMap.count >= _inMemoryCount){ + break; + } + } +} + + + +- (NSString *)cacheDir +{ + static NSString *cachePath = nil; + if (!cachePath) { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *cacheDirectory = [paths objectAtIndex:0]; + cachePath = [cacheDirectory stringByAppendingPathComponent:@"FlutterScreenshots"]; + } + + BOOL dir = NO; + if(![[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&dir]){ + NSError *eror = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:cachePath + withIntermediateDirectories:YES + attributes:nil + error:&eror]; + if (eror) { + NSLog(@"%@",eror); + } + } + + return cachePath; +} + +@end diff --git a/ios/Classes/1.0/FLBFlutterEngine.h b/ios/Classes/1.0/Support/Cache/FLBStackCacheObjectImg.h similarity index 85% rename from ios/Classes/1.0/FLBFlutterEngine.h rename to ios/Classes/1.0/Support/Cache/FLBStackCacheObjectImg.h index 85e0851..9ce0dc5 100755 --- a/ios/Classes/1.0/FLBFlutterEngine.h +++ b/ios/Classes/1.0/Support/Cache/FLBStackCacheObjectImg.h @@ -23,15 +23,15 @@ */ #import <Foundation/Foundation.h> -#import "FLBFlutterViewProvider.h" -NS_ASSUME_NONNULL_BEGIN +#import "FLBStackCache.h" -#if RELEASE_1_0 +@interface FLBStackCacheObjectImg : NSObject<FLBStackCacheObject> -@interface FLBFlutterEngine : NSObject<FLBFlutterViewProvider> -@end +@property (nonatomic,copy) NSString *key; + +- (instancetype)initWithImage:(UIImage *)image; -#endif +- (UIImage *)image; -NS_ASSUME_NONNULL_END +@end diff --git a/ios/Classes/1.0/Support/Cache/FLBStackCacheObjectImg.m b/ios/Classes/1.0/Support/Cache/FLBStackCacheObjectImg.m new file mode 100755 index 0000000..b95eef1 --- /dev/null +++ b/ios/Classes/1.0/Support/Cache/FLBStackCacheObjectImg.m @@ -0,0 +1,116 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Alibaba Group + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import "FLBStackCacheObjectImg.h" + +@interface FLBStackCacheObjectImg() +@property (nonatomic,strong) UIImage *image; +@end + +@implementation FLBStackCacheObjectImg + +- (instancetype)initWithImage:(UIImage *)image +{ + if (self = [super init]) { + _image = image; + } + + return self; +} + + + ++ (BOOL)loadFromFileWithKey:(NSString *)key + queue:(dispatch_queue_t)queue + cache:(FLBStackCache *)cache + completion:(void (^)(NSError *, id<FLBStackCacheObject>))completion +{ + dispatch_async(queue, ^{ + UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self filePathByKey:key dirPath:cache.cacheDir]]; + if (completion) { + if (image) { + FLBStackCacheObjectImg *ob = [[FLBStackCacheObjectImg alloc] initWithImage:image]; + ob.key = key; + completion(nil,ob); + }else{ + completion([NSError new],nil); + } + } + }); + + return YES; +} + ++ (NSString *)filePathByKey:(NSString *)key dirPath:(NSString *)cacheDir +{ + key = [key stringByReplacingOccurrencesOfString:@"/" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@":" withString:@""]; + NSString *path = [cacheDir stringByAppendingPathComponent:key]; + return path; +} + +- (BOOL)writeToFileWithKey:(NSString *)key + queue:(dispatch_queue_t)queue + cache:(FLBStackCache *)cache + completion:(void (^)(NSError *, NSString *))completion +{ + if(!_image){ + return NO; + } + + dispatch_async(queue, ^{ + NSData *imgData = UIImagePNGRepresentation(self.image); + NSString *filePath = [FLBStackCacheObjectImg filePathByKey:key dirPath:cache.cacheDir]; + [imgData writeToFile:filePath atomically:YES]; + if (completion) { + completion(nil,key); + } + }); + + return YES; +} + +- (BOOL)removeCachedFileWithKey:(NSString *)key + queue:(dispatch_queue_t)queue + cache:(FLBStackCache *)cache + completion:(void (^)(NSError *, NSString *))completion +{ + if(!key){ + return NO; + } + + dispatch_async(queue, ^{ + NSString *filePath = [FLBStackCacheObjectImg filePathByKey:key dirPath:cache.cacheDir]; + NSError *err = nil; + [NSFileManager.defaultManager removeItemAtPath:filePath error:&err]; + if (completion) { + completion(err,key); + } + }); + + return YES; +} + + +@end diff --git a/ios/Classes/1.0/Support/Memory/FLBMemoryInspector.h b/ios/Classes/1.0/Support/Memory/FLBMemoryInspector.h new file mode 100755 index 0000000..f04b3f4 --- /dev/null +++ b/ios/Classes/1.0/Support/Memory/FLBMemoryInspector.h @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Alibaba Group + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import <Foundation/Foundation.h> + +#define kFLBMemoryInspectorChangedNotification @"__FlutterMemoryInspectorChangedNotification__" +#define kFLBMemoryInspectorKeyCondition @"condition" + +typedef NS_ENUM(NSUInteger,FLBMemoryCondition) { + FLBMemoryConditionUnknown, + FLBMemoryConditionNormal, + FLBMemoryConditionLowMemory, + FLBMemoryConditionExtremelyLow, + FLBMemoryConditionAboutToDie +}; + +@interface FLBMemoryInspector : NSObject + ++ (instancetype)sharedInstance; + +- (FLBMemoryCondition)currentCondition; +- (int64_t)currentFootPrint; +- (int64_t)deviceMemory; +- (BOOL)smallMemoryDevice; + +@end diff --git a/ios/Classes/1.0/Support/Memory/FLBMemoryInspector.mm b/ios/Classes/1.0/Support/Memory/FLBMemoryInspector.mm new file mode 100755 index 0000000..2854b76 --- /dev/null +++ b/ios/Classes/1.0/Support/Memory/FLBMemoryInspector.mm @@ -0,0 +1,157 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Alibaba Group + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import "FLBMemoryInspector.h" + +#include <mach/mach.h> +#include <stdlib.h> +#include <sys/sysctl.h> + +#define MB(_v_) (_v_*1024*1024) +#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) +#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) + +@interface FLBMemoryInspector() +@property(nonatomic,assign) FLBMemoryCondition condition; +@end + +@implementation FLBMemoryInspector + ++ (instancetype)sharedInstance +{ + static id sInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sInstance = [[self.class alloc] init]; + }); + + return sInstance; +} + +static bool isHighterThanIos9(){ + bool ret = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0.0"); + return ret; +} + +static int64_t memoryFootprint() +{ + task_vm_info_data_t vmInfo; + mach_msg_type_number_t count = TASK_VM_INFO_COUNT; + kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count); + if (result != KERN_SUCCESS) + return -1; + return vmInfo.phys_footprint; +} + + +static int64_t _memoryWarningLimit() +{ + size_t size; + sysctlbyname("hw.machine", NULL, &size, NULL, 0); + char *machine =(char *) malloc(size); + sysctlbyname("hw.machine", machine, &size, NULL, 0); + NSString *platform = [NSString stringWithUTF8String:machine]; + free(machine); + + if ([platform isEqualToString:@"iPhone5,1"]) return MB(600); + if ([platform isEqualToString:@"iPhone5,2"]) return MB(600); + if ([platform isEqualToString:@"iPhone5,3"]) return MB(600); + if ([platform isEqualToString:@"iPhone5,4"]) return MB(600); + if ([platform isEqualToString:@"iPhone6,1"]) return MB(600); + if ([platform isEqualToString:@"iPhone6,2"]) return MB(600); + if ([platform isEqualToString:@"iPhone7,1"]) return MB(600); + if ([platform isEqualToString:@"iPhone7,2"]) return MB(600); + if ([platform isEqualToString:@"iPhone8,1"]) return MB(1280); + if ([platform isEqualToString:@"iPhone8,2"]) return MB(1280); + if ([platform isEqualToString:@"iPhone8,4"]) return MB(1280); + if ([platform isEqualToString:@"iPhone9,1"]) return MB(1280); + if ([platform isEqualToString:@"iPhone9,2"]) return MB(1950); + if ([platform isEqualToString:@"iPhone9,3"]) return MB(1280); + if ([platform isEqualToString:@"iPhone9,4"]) return MB(1950); + if ([platform isEqualToString:@"iPhone10,1"]) return MB(1280); + if ([platform isEqualToString:@"iPhone10,2"]) return MB(1950); + if ([platform isEqualToString:@"iPhone10,3"]) return MB(1950); + if ([platform isEqualToString:@"iPhone10,4"]) return MB(1280); + if ([platform isEqualToString:@"iPhone10,5"]) return MB(1950); + if ([platform isEqualToString:@"iPhone10,6"]) return MB(1950); + + return 0; +} + +static int64_t getLimit(){ + const static size_t l = _memoryWarningLimit(); + return l; +} + +- (int64_t)deviceMemory +{ + int64_t size = [NSProcessInfo processInfo].physicalMemory; + return size; +} + +- (BOOL)smallMemoryDevice +{ + if([self deviceMemory] <= MB(1024)){ + return YES; + }else{ + return NO; + } +} + +- (FLBMemoryCondition)currentCondition +{ + FLBMemoryCondition newCondition = FLBMemoryConditionUnknown; + + + if(!isHighterThanIos9() || getLimit() <= 0){ + newCondition = FLBMemoryConditionUnknown; + }else if(memoryFootprint() < getLimit() * 0.40){ + newCondition = FLBMemoryConditionNormal; + }else if(memoryFootprint() < getLimit() * 0.60){ + newCondition = FLBMemoryConditionLowMemory; + }else if(memoryFootprint() < getLimit() * 0.80){ + newCondition = FLBMemoryConditionExtremelyLow; + }else{ + newCondition = FLBMemoryConditionAboutToDie; + } + + if (newCondition != self.condition) { + [[NSNotificationCenter defaultCenter] postNotificationName:kFLBMemoryInspectorChangedNotification + object:@{kFLBMemoryInspectorKeyCondition:@(newCondition)}]; + } + + self.condition = newCondition; + + return newCondition; +} + +- (int64_t)currentFootPrint +{ + return memoryFootprint(); +} + +@end -- 2.26.2