suyao-lingoace
Committed by GitHub

Fix Infinite loop on iOS (#156)

* [Fix][*]fix Infinite loop of iOS

Signed-off-by: suyao-lingoace <yao.su@pplingo.com>

* Fix Infinite loop on iOS

When you use setter method in it's KVO,Will cause infinite loop,So I hook the setter method ,If the enable is 'YES' ,I ignore other call the setter.

Signed-off-by: suyao-lingoace <yao.su@pplingo.com>

* Update wakelock/ios/Classes/WakelockPlugin.m

Co-authored-by: creativecreatorormaybenot <creativecreatorormaybenot@gmail.com>

* Update wakelock/ios/Classes/WakelockPlugin.m

Co-authored-by: creativecreatorormaybenot <creativecreatorormaybenot@gmail.com>

* Update wakelock/ios/Classes/WakelockPlugin.m

Co-authored-by: creativecreatorormaybenot <creativecreatorormaybenot@gmail.com>
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 archiveVersion = 1; 3 archiveVersion = 1;
4 classes = { 4 classes = {
5 }; 5 };
6 - objectVersion = 46; 6 + objectVersion = 50;
7 objects = { 7 objects = {
8 8
9 /* Begin PBXBuildFile section */ 9 /* Begin PBXBuildFile section */
@@ -76,7 +76,6 @@ @@ -76,7 +76,6 @@
76 A3A052DAD735CA9CF9731DD7 /* Pods-Runner.release.xcconfig */, 76 A3A052DAD735CA9CF9731DD7 /* Pods-Runner.release.xcconfig */,
77 06B046091A6718E60BC8F2E0 /* Pods-Runner.profile.xcconfig */, 77 06B046091A6718E60BC8F2E0 /* Pods-Runner.profile.xcconfig */,
78 ); 78 );
79 - name = Pods;  
80 path = Pods; 79 path = Pods;
81 sourceTree = "<group>"; 80 sourceTree = "<group>";
82 }; 81 };
@@ -338,9 +337,13 @@ @@ -338,9 +337,13 @@
338 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 337 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
339 CLANG_ENABLE_MODULES = YES; 338 CLANG_ENABLE_MODULES = YES;
340 CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 339 CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
  340 + DEVELOPMENT_TEAM = "";
341 ENABLE_BITCODE = NO; 341 ENABLE_BITCODE = NO;
342 INFOPLIST_FILE = Runner/Info.plist; 342 INFOPLIST_FILE = Runner/Info.plist;
343 - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 343 + LD_RUNPATH_SEARCH_PATHS = (
  344 + "$(inherited)",
  345 + "@executable_path/Frameworks",
  346 + );
344 PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample; 347 PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample;
345 PRODUCT_NAME = "$(TARGET_NAME)"; 348 PRODUCT_NAME = "$(TARGET_NAME)";
346 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 349 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -449,7 +452,8 @@ @@ -449,7 +452,8 @@
449 MTL_ENABLE_DEBUG_INFO = NO; 452 MTL_ENABLE_DEBUG_INFO = NO;
450 SDKROOT = iphoneos; 453 SDKROOT = iphoneos;
451 SUPPORTED_PLATFORMS = iphoneos; 454 SUPPORTED_PLATFORMS = iphoneos;
452 - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 455 + SWIFT_COMPILATION_MODE = wholemodule;
  456 + SWIFT_OPTIMIZATION_LEVEL = "-O";
453 TARGETED_DEVICE_FAMILY = "1,2"; 457 TARGETED_DEVICE_FAMILY = "1,2";
454 VALIDATE_PRODUCT = YES; 458 VALIDATE_PRODUCT = YES;
455 }; 459 };
@@ -462,9 +466,13 @@ @@ -462,9 +466,13 @@
462 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 466 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
463 CLANG_ENABLE_MODULES = YES; 467 CLANG_ENABLE_MODULES = YES;
464 CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 468 CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
  469 + DEVELOPMENT_TEAM = "";
465 ENABLE_BITCODE = NO; 470 ENABLE_BITCODE = NO;
466 INFOPLIST_FILE = Runner/Info.plist; 471 INFOPLIST_FILE = Runner/Info.plist;
467 - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 472 + LD_RUNPATH_SEARCH_PATHS = (
  473 + "$(inherited)",
  474 + "@executable_path/Frameworks",
  475 + );
468 PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample; 476 PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample;
469 PRODUCT_NAME = "$(TARGET_NAME)"; 477 PRODUCT_NAME = "$(TARGET_NAME)";
470 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 478 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -481,9 +489,13 @@ @@ -481,9 +489,13 @@
481 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 489 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
482 CLANG_ENABLE_MODULES = YES; 490 CLANG_ENABLE_MODULES = YES;
483 CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 491 CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
  492 + DEVELOPMENT_TEAM = "";
484 ENABLE_BITCODE = NO; 493 ENABLE_BITCODE = NO;
485 INFOPLIST_FILE = Runner/Info.plist; 494 INFOPLIST_FILE = Runner/Info.plist;
486 - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 495 + LD_RUNPATH_SEARCH_PATHS = (
  496 + "$(inherited)",
  497 + "@executable_path/Frameworks",
  498 + );
487 PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample; 499 PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample;
488 PRODUCT_NAME = "$(TARGET_NAME)"; 500 PRODUCT_NAME = "$(TARGET_NAME)";
489 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 501 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -27,8 +27,6 @@ @@ -27,8 +27,6 @@
27 selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" 27 selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28 selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" 28 selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29 shouldUseLaunchSchemeArgsEnv = "YES"> 29 shouldUseLaunchSchemeArgsEnv = "YES">
30 - <Testables>  
31 - </Testables>  
32 <MacroExpansion> 30 <MacroExpansion>
33 <BuildableReference 31 <BuildableReference
34 BuildableIdentifier = "primary" 32 BuildableIdentifier = "primary"
@@ -38,8 +36,8 @@ @@ -38,8 +36,8 @@
38 ReferencedContainer = "container:Runner.xcodeproj"> 36 ReferencedContainer = "container:Runner.xcodeproj">
39 </BuildableReference> 37 </BuildableReference>
40 </MacroExpansion> 38 </MacroExpansion>
41 - <AdditionalOptions>  
42 - </AdditionalOptions> 39 + <Testables>
  40 + </Testables>
43 </TestAction> 41 </TestAction>
44 <LaunchAction 42 <LaunchAction
45 buildConfiguration = "Debug" 43 buildConfiguration = "Debug"
@@ -61,8 +59,6 @@ @@ -61,8 +59,6 @@
61 ReferencedContainer = "container:Runner.xcodeproj"> 59 ReferencedContainer = "container:Runner.xcodeproj">
62 </BuildableReference> 60 </BuildableReference>
63 </BuildableProductRunnable> 61 </BuildableProductRunnable>
64 - <AdditionalOptions>  
65 - </AdditionalOptions>  
66 </LaunchAction> 62 </LaunchAction>
67 <ProfileAction 63 <ProfileAction
68 buildConfiguration = "Profile" 64 buildConfiguration = "Profile"
1 -#import <Foundation/Foundation.h>  
2 -  
3 -NS_ASSUME_NONNULL_BEGIN  
4 -  
5 -@interface IdleTimerDisabledObserver : NSObject  
6 -  
7 -@property BOOL enable;  
8 -  
9 -+ (IdleTimerDisabledObserver*)singleInstance;  
10 -  
11 -- (void) beginObserving;  
12 -  
13 -- (void) endObserving;  
14 -  
15 -@end  
16 -  
17 -NS_ASSUME_NONNULL_END  
1 -#import "IdleTimerDisabledObserver.h"  
2 -  
3 -@interface IdleTimerDisabledObserver() {  
4 - int numObservers;  
5 -}  
6 -  
7 -@end  
8 -  
9 -static void * mKeyPathObserverContextApplicationIsIdleTimerDisabled = &mKeyPathObserverContextApplicationIsIdleTimerDisabled;  
10 -  
11 -@implementation IdleTimerDisabledObserver  
12 -  
13 -+ (IdleTimerDisabledObserver*)singleInstance {  
14 - static IdleTimerDisabledObserver *instance = nil;  
15 - static dispatch_once_t onceToken;  
16 - dispatch_once(&onceToken, ^{  
17 - instance = [[self alloc] init];  
18 - });  
19 - return instance;  
20 -}  
21 -  
22 -- (void)beginObserving {  
23 - if (numObservers == 0) {  
24 - [UIApplication.sharedApplication addObserver:self  
25 - forKeyPath:@"idleTimerDisabled"  
26 - options:NSKeyValueObservingOptionNew  
27 - context:mKeyPathObserverContextApplicationIsIdleTimerDisabled];  
28 - }  
29 -  
30 - numObservers ++;  
31 -}  
32 -  
33 -- (void)endObserving {  
34 - numObservers --;  
35 -  
36 - if (numObservers == 0) {  
37 - [UIApplication.sharedApplication removeObserver:self forKeyPath:@"idleTimerDisabled" context:mKeyPathObserverContextApplicationIsIdleTimerDisabled];  
38 - }  
39 -}  
40 -  
41 -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {  
42 - if (context == mKeyPathObserverContextApplicationIsIdleTimerDisabled) {  
43 - if (UIApplication.sharedApplication.idleTimerDisabled != self.enable) {  
44 - UIApplication.sharedApplication.idleTimerDisabled = self.enable;  
45 - }  
46 - } else {  
47 - [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];  
48 - }  
49 -}  
50 -  
51 -  
52 -@end  
  1 +//
  2 +// UIApplication+idleTimerLock.h
  3 +// wakelock
  4 +//
  5 +// Created by suyao on 2021/12/17.
  6 +//
  7 +
  8 +#import <UIKit/UIKit.h>
  9 +
  10 +NS_ASSUME_NONNULL_BEGIN
  11 +
  12 +@interface UIApplication (idleTimerLock)
  13 +
  14 +- (void)lock_idleTimerlockEnable:(BOOL)enable;
  15 +
  16 +@end
  17 +
  18 +NS_ASSUME_NONNULL_END
  1 +//
  2 +// UIApplication+idleTimerLock.m
  3 +// wakelock
  4 +//
  5 +// Created by suyao on 2021/12/17.
  6 +//
  7 +
  8 +#import "UIApplication+idleTimerLock.h"
  9 +#import <objc/runtime.h>
  10 +
  11 +static NSString *idleTimerLockKey = @"idleTimerLockKey";
  12 +
  13 +
  14 +@implementation UIApplication (idleTimerLock)
  15 +
  16 ++ (void)load {
  17 + Method setIdleTimerDisabled = class_getInstanceMethod(self, @selector(setIdleTimerDisabled:));
  18 +
  19 + Method lock_setIdleTimerDisabled = class_getInstanceMethod(self, @selector(lock_setIdleTimerDisabled:));
  20 +
  21 + method_exchangeImplementations(setIdleTimerDisabled, lock_setIdleTimerDisabled);
  22 +}
  23 +
  24 +- (void)lock_setIdleTimerDisabled:(BOOL)enable {
  25 + if ([self lock_idleTimerlockEnable]) {
  26 + return;
  27 + }
  28 + [self lock_setIdleTimerDisabled:enable];
  29 +}
  30 +
  31 +- (void)lock_idleTimerlockEnable:(BOOL)enable {
  32 + objc_setAssociatedObject(self, &idleTimerLockKey, @(enable), OBJC_ASSOCIATION_COPY);
  33 +}
  34 +
  35 +- (BOOL)lock_idleTimerlockEnable
  36 +{
  37 + return [objc_getAssociatedObject(self, &idleTimerLockKey) boolValue];
  38 +}
  39 +
  40 +@end
1 #import "WakelockPlugin.h" 1 #import "WakelockPlugin.h"
2 -#import "IdleTimerDisabledObserver.h"  
3 #import "messages.h" 2 #import "messages.h"
  3 +#import "UIApplication+idleTimerLock.h"
4 4
5 5
6 @interface WakelockPlugin () <FLTWakelockApi> 6 @interface WakelockPlugin () <FLTWakelockApi>
@@ -13,37 +13,37 @@ @@ -13,37 +13,37 @@
13 + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { 13 + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
14 WakelockPlugin* instance = [[WakelockPlugin alloc] init]; 14 WakelockPlugin* instance = [[WakelockPlugin alloc] init];
15 FLTWakelockApiSetup(registrar.messenger, instance); 15 FLTWakelockApiSetup(registrar.messenger, instance);
16 -  
17 - [[IdleTimerDisabledObserver singleInstance] beginObserving];  
18 } 16 }
19 17
20 - (void)toggleMsg:(FLTToggleMessage*)input error:(FlutterError**)error { 18 - (void)toggleMsg:(FLTToggleMessage*)input error:(FlutterError**)error {
21 - NSNumber *enable = input.enable;  
22 - self.enable = enable.boolValue;  
23 - NSNumber *enabled = [NSNumber numberWithBool:[[UIApplication sharedApplication] isIdleTimerDisabled]];  
24 -  
25 - if (![enable isEqualToNumber:enabled]) {  
26 - [[UIApplication sharedApplication] setIdleTimerDisabled:enable.boolValue]; 19 + BOOL enable = [input.enable boolValue];
  20 + if (!enable) {
  21 + [[UIApplication sharedApplication] lock_idleTimerlockEnable:enable];//should disable first
  22 + [self setIdleTimerDisabled:enable];
  23 + } else {
  24 + [self setIdleTimerDisabled:enable];
  25 + [[UIApplication sharedApplication] lock_idleTimerlockEnable:enable];
  26 + }
  27 + self.enable = enable;
  28 +}
  29 +
  30 +- (void)setIdleTimerDisabled:(BOOL)enable {
  31 + BOOL enabled = [[UIApplication sharedApplication] isIdleTimerDisabled];
  32 + if (enable!= enabled) {
  33 + [[UIApplication sharedApplication] setIdleTimerDisabled:enable];
27 } 34 }
28 } 35 }
29 36
  37 +
30 - (FLTIsEnabledMessage*)isEnabledWithError:(FlutterError* __autoreleasing *)error { 38 - (FLTIsEnabledMessage*)isEnabledWithError:(FlutterError* __autoreleasing *)error {
31 NSNumber *enabled = [NSNumber numberWithBool:[[UIApplication sharedApplication] isIdleTimerDisabled]]; 39 NSNumber *enabled = [NSNumber numberWithBool:[[UIApplication sharedApplication] isIdleTimerDisabled]];
32 -  
33 FLTIsEnabledMessage* result = [[FLTIsEnabledMessage alloc] init]; 40 FLTIsEnabledMessage* result = [[FLTIsEnabledMessage alloc] init];
34 result.enabled = enabled; 41 result.enabled = enabled;
35 -  
36 return result; 42 return result;
37 } 43 }
38 44
39 - (void)setEnable:(BOOL)enable { 45 - (void)setEnable:(BOOL)enable {
40 - [IdleTimerDisabledObserver singleInstance].enable = enable;  
41 -  
42 _enable = enable; 46 _enable = enable;
43 } 47 }
44 48
45 -- (void)dealloc {  
46 - [[IdleTimerDisabledObserver singleInstance] endObserving];  
47 -}  
48 -  
49 @end 49 @end