问题
I've been trying to use SBSettings toggles to turn things on or off--like Airplane Mode, WiFi, SSH, etc--but I just can't figure out why my code works for some of these toggles and not all. Granted, I'm only talking about "simple" toggles; not toggles that bring up their own window with their own controls like for volume or brightness. I've been able to successfully turn on/off 3G, data, my ringer, the mywi toggle... things like that, but I can't figure why some of the toggles--Airplane Mode, Bluetooth, WiFi--on my phone won't respond to the same code that works with the other things mentioned above.
Here's some of the code I'm using:
//.h
#import <UIKit/UIKit.h>
#import <sys/stat.h>
#include "/usr/include/dlfcn.h"
typedef enum toggleTypes
{
SIMPLE,
NOT_SIMPLE
} ToggleTypes;
typedef bool (*BoolFn)();
typedef void (*VoidBoolFn)(bool b);
@interface Toggle : NSObject
@property (strong, nonatomic) NSString *toggleName;
@property (nonatomic) ToggleTypes toggleType;
- (Toggle *) initWithFullPath:(NSString *) togglePath;
- (BOOL) isEnabled;
- (BOOL) isCapable;
- (BOOL) getStateFast;
- (void) setState:(BOOL) state;
@end
//.m
@implementation Toggle {
@private
void *_dylibHandle;
BoolFn _isCapable;
BoolFn _isEnabled;
BoolFn _getStateFast;
VoidBoolFn _setState;
}
@synthesize toggleName = _toggleName;
@synthesize toggleType = _toggleType;
- (Toggle *) initWithFullPath:(NSString *) togglePath
{
self.toggleName = [[togglePath stringByDeletingLastPathComponent] lastPathComponent];
const char *fullName = [togglePath UTF8String];
struct stat fstat;
if( stat(fullName, &fstat) != 0 )
{
NSLog(@"Reading error for file %s", fullName);
return nil;
}
dlerror();
_dylibHandle = dlopen(fullName, RTLD_LAZY | RTLD_LOCAL );
if( !_dylibHandle)
{
NSLog(@"dlopen encountered an error and did not open file: %s", fullName);
return nil;
}
dlerror();
_isCapable = dlsym(_dylibHandle, "isCapable");
char *error = dlerror();
if( !_isCapable )
{
NSLog(@"An error was encountered while loading symbol \"isCapable\"\nFile: %s\nError: %s", fullName, error);
return nil;
}
_isEnabled = dlsym(_dylibHandle, "isEnabled");
error = dlerror();
if( !_isCapable )
{
NSLog(@"An error was encountered while loading symbol \"isEnabled\"\nFile: %s\nError: %s", fullName, error);
return nil;
}
_getStateFast = dlsym(_dylibHandle, "getStateFast");
error = dlerror();
if( !_isCapable )
{
NSLog(@"An error was encountered while loading symbol \"getStateFast\"\nFile: %s\nError: %s", fullName, error);
return nil;
}
_setState = dlsym(_dylibHandle, "setState");
error = dlerror();
if( !_isCapable )
{
NSLog(@"An error was encountered while loading symbol \"getStateFast\"\nFile: %s\nError: %s", fullName, error);
return nil;
}
NSArray *windowsBefore = [[[[UIApplication sharedApplication] windows] objectAtIndex:0] subviews];
[self setState:[self isEnabled]];
NSArray *windowsAfter = [[[[UIApplication sharedApplication] windows] objectAtIndex:0] subviews];
if( [windowsAfter count] > [windowsBefore count] ) {
self.toggleType = NOT_SIMPLE;
for (UIView *view in windowsAfter) {
if( ![windowsBefore containsObject:view] )
[view removeFromSuperview];
}
} else {
self.toggleType = SIMPLE;
}
return self;
}
- (BOOL) isEnabled
{
return _isEnabled();
}
- (BOOL) isCapable
{
return _isCapable();
}
- (BOOL) getStateFast
{
return _getStateFast();
}
- (void) setState:(BOOL) state
{
_setState(state);
}
- (void) dealloc
{
dlclose(_dylibHandle);
}
@end
The code that calls initWithFullPath
:
if( [directoryToggleNames objectForKey:toggleName] == nil ) {
if ((strlen(SBTOGGLES_PATH) + strlen([toggleName UTF8String] + strlen("/Toggle.dylib")) + 1) > _POSIX_PATH_MAX) {
NSLog(@"Toggle %@ has a path name that is too long", toggleName);
return nil;
}
char fullName[_POSIX_PATH_MAX + 1];
strcpy(fullName, SBTOGGLES_PATH);
strcat(fullName, [toggleName UTF8String]);
strcat(fullName, "/Toggle.dylib");
NSString *fullPath = [NSString stringWithUTF8String:fullName];
return [[OSToggle alloc] initWithFullPath:fullPath];
}
return [[OSToggle alloc] initWithFullPath:[directoryToggleNames objectForKey:toggleName]];
The code that uses the code above and the toggle class itself:
ToggleScanner *scanner = [ToggleScanner getInstance];
NSDictionary *toggleDict = [self getToggleDictionary];
for (ToggleBase *t in [toggleDict allValues] ) {
OSToggle *toggle = [scanner getToggleByName:t.name];
if( [t.type isEqualToString:@"simple"] ) {
NSLog(@"isCapable: %@; isEnabled: %@", ( [toggle isCapable] ? @"YES" : @"NO" ), ( [toggle isEnabled] ? @"YES" : @"NO" ));
[toggle setState:t.state.boolValue];
NSLog(@"Set toggle, %@, to %@; result isEnabled: %@", t.name, ( t.state.boolValue ? @"YES" : @"NO" ), ( [toggle isEnabled] ? @"YES" : @"NO" ) );
} else {
NSLog(@"Toggle is not a simple type");
}
}
ToggleScanner just looks in the SBSettings toggle directory and builds a dictionary based on the toggles it finds there. getToggleDict is a method that takes a NSData object out of CoreData and turns it into a set of toggles and state that I can, in turn, execute. ToggleBase is just an information holding class; it has no methods.
Its rough, but it works on some of the toggles. The question is: Is there something I'm doing wrong here? Both the Airplane Mode and the 3G toggle are simple on/off switches, yet this code works on the 3G toggle but not the Airplane Mode one. Any ideas, comments, and/or suggestions as to why this is?
Edit 1: Added code that calls the toggle class and some descriptions about it.
回答1:
My idea is similar to your original idea, I try to hook up to each toggle.dylib of SBSetting to turn on/off 3G, Wi-Fi, MyFi. However, I could only make it work for 3G toggle. I could not figure out how to make it work for MyFi toggle too. what version of MyFi did you use?
回答2:
by the way, I also tested other toggle such as location, data, they all worked. As I checked the source code, of location toggle, it just simply changes the property of locationd.plist file while for WiFi toggle case, it requires to utilize the private framework SBWiFimanager, so that maybe the problem. When you use SB framework, you need to have springboard context. Therefore, if you call toggle's method from an app, it does not have springboard context. So think it is the reason while WiFi, and Airplane toggle do not work.
来源:https://stackoverflow.com/questions/12363662/using-sbsettings-toggles-to-turn-things-on-or-off