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 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
... ... @@ -76,7 +76,6 @@
A3A052DAD735CA9CF9731DD7 /* Pods-Runner.release.xcconfig */,
06B046091A6718E60BC8F2E0 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
... ... @@ -338,9 +337,13 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
... ... @@ -449,7 +452,8 @@
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
... ... @@ -462,9 +466,13 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
... ... @@ -481,9 +489,13 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = creativemaybeno.wakelockExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
... ...
... ... @@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
... ... @@ -38,8 +36,8 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
... ... @@ -61,8 +59,6 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
... ...
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface IdleTimerDisabledObserver : NSObject
@property BOOL enable;
+ (IdleTimerDisabledObserver*)singleInstance;
- (void) beginObserving;
- (void) endObserving;
@end
NS_ASSUME_NONNULL_END
#import "IdleTimerDisabledObserver.h"
@interface IdleTimerDisabledObserver() {
int numObservers;
}
@end
static void * mKeyPathObserverContextApplicationIsIdleTimerDisabled = &mKeyPathObserverContextApplicationIsIdleTimerDisabled;
@implementation IdleTimerDisabledObserver
+ (IdleTimerDisabledObserver*)singleInstance {
static IdleTimerDisabledObserver *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
- (void)beginObserving {
if (numObservers == 0) {
[UIApplication.sharedApplication addObserver:self
forKeyPath:@"idleTimerDisabled"
options:NSKeyValueObservingOptionNew
context:mKeyPathObserverContextApplicationIsIdleTimerDisabled];
}
numObservers ++;
}
- (void)endObserving {
numObservers --;
if (numObservers == 0) {
[UIApplication.sharedApplication removeObserver:self forKeyPath:@"idleTimerDisabled" context:mKeyPathObserverContextApplicationIsIdleTimerDisabled];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == mKeyPathObserverContextApplicationIsIdleTimerDisabled) {
if (UIApplication.sharedApplication.idleTimerDisabled != self.enable) {
UIApplication.sharedApplication.idleTimerDisabled = self.enable;
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
//
// UIApplication+idleTimerLock.h
// wakelock
//
// Created by suyao on 2021/12/17.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIApplication (idleTimerLock)
- (void)lock_idleTimerlockEnable:(BOOL)enable;
@end
NS_ASSUME_NONNULL_END
... ...
//
// UIApplication+idleTimerLock.m
// wakelock
//
// Created by suyao on 2021/12/17.
//
#import "UIApplication+idleTimerLock.h"
#import <objc/runtime.h>
static NSString *idleTimerLockKey = @"idleTimerLockKey";
@implementation UIApplication (idleTimerLock)
+ (void)load {
Method setIdleTimerDisabled = class_getInstanceMethod(self, @selector(setIdleTimerDisabled:));
Method lock_setIdleTimerDisabled = class_getInstanceMethod(self, @selector(lock_setIdleTimerDisabled:));
method_exchangeImplementations(setIdleTimerDisabled, lock_setIdleTimerDisabled);
}
- (void)lock_setIdleTimerDisabled:(BOOL)enable {
if ([self lock_idleTimerlockEnable]) {
return;
}
[self lock_setIdleTimerDisabled:enable];
}
- (void)lock_idleTimerlockEnable:(BOOL)enable {
objc_setAssociatedObject(self, &idleTimerLockKey, @(enable), OBJC_ASSOCIATION_COPY);
}
- (BOOL)lock_idleTimerlockEnable
{
return [objc_getAssociatedObject(self, &idleTimerLockKey) boolValue];
}
@end
... ...
#import "WakelockPlugin.h"
#import "IdleTimerDisabledObserver.h"
#import "messages.h"
#import "UIApplication+idleTimerLock.h"
@interface WakelockPlugin () <FLTWakelockApi>
... ... @@ -13,37 +13,37 @@
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
WakelockPlugin* instance = [[WakelockPlugin alloc] init];
FLTWakelockApiSetup(registrar.messenger, instance);
[[IdleTimerDisabledObserver singleInstance] beginObserving];
}
- (void)toggleMsg:(FLTToggleMessage*)input error:(FlutterError**)error {
NSNumber *enable = input.enable;
self.enable = enable.boolValue;
NSNumber *enabled = [NSNumber numberWithBool:[[UIApplication sharedApplication] isIdleTimerDisabled]];
BOOL enable = [input.enable boolValue];
if (!enable) {
[[UIApplication sharedApplication] lock_idleTimerlockEnable:enable];//should disable first
[self setIdleTimerDisabled:enable];
} else {
[self setIdleTimerDisabled:enable];
[[UIApplication sharedApplication] lock_idleTimerlockEnable:enable];
}
self.enable = enable;
}
if (![enable isEqualToNumber:enabled]) {
[[UIApplication sharedApplication] setIdleTimerDisabled:enable.boolValue];
- (void)setIdleTimerDisabled:(BOOL)enable {
BOOL enabled = [[UIApplication sharedApplication] isIdleTimerDisabled];
if (enable!= enabled) {
[[UIApplication sharedApplication] setIdleTimerDisabled:enable];
}
}
- (FLTIsEnabledMessage*)isEnabledWithError:(FlutterError* __autoreleasing *)error {
NSNumber *enabled = [NSNumber numberWithBool:[[UIApplication sharedApplication] isIdleTimerDisabled]];
FLTIsEnabledMessage* result = [[FLTIsEnabledMessage alloc] init];
result.enabled = enabled;
return result;
}
- (void)setEnable:(BOOL)enable {
[IdleTimerDisabledObserver singleInstance].enable = enable;
_enable = enable;
}
- (void)dealloc {
[[IdleTimerDisabledObserver singleInstance] endObserving];
}
@end
... ...