How do i find out the Wifi signal strengths(RSSI) in iOS8 ?
I know that Apple restricts apps from accessing the Wi-Fi data/API directly and will not be accepted in AppStore. I found a private API called Stumbler which is supposed to be doing the same. Here is the link to it. Accessing & Using the MobileWiFi.framework
networks = [[NSMutableDictionary alloc] init];
void* library = dlopen("/System/Library/SystemConfiguration/IPConfiguration.bundle/IPConfiguration", RTLD_LAZY);
int (*apple80211Open)(void*) = (int(*)(void*))dlsym(library, "Apple80211Open");
int (*apple80211Bind)(void*, NSString*) = (int(*)(void*, NSString*))dlsym(library, "Apple80211BindToInterface");
apple80211Close = (int(*)(void*))dlsym(library, "Apple80211Close");
apple80211Scan= (int(*)(void*, NSArray**, void*))dlsym(library, "Apple80211Scan");
void *airport = NULL;
apple80211Open(&airport);
apple80211Bind(airport, #"en0");
NSArray* arrNetworks = nil;
apple80211Scan(airport, &arrNetworks, (__bridge void *)(networks));
//"networks" is an array of NSDictionary objects for all the visible Wi-Fi networks
apple80211Close(airport);
dlclose(library);
Somehow this is not working in iOS8. Anyone has any idea how to get this working?? Thanks for the help !!
Related
I am working on a requirement where i need to monitor changes in Thunderbolt port connection. (When Thunderbolt cable is connected or disconnected).
I tried to use IOServiceMatching(kIOUSBInterfaceClassName) from IOKit framework but i cannot monitor changes on Thunderbolt port.
Is there any way i can achieve it? Any help is appreciated.
Thunderbolt devices (except displays that use the DisplayPort portion of the Thunderbolt port) are PCI devices, not USB, so they will show up in the IOService registry as IOPCIDevices. They will however also show up as IOThunderboltPort objects in the Thunderbolt subtree, where the "PCI Path" property will indicate the IOService path to the relevant IOPCIDevice. By monitoring the appearance and disappearance of IOThunderboltPort services, and checking their PCI Path property, you can avoid matching other kinds of PCI devices.
To illustrate what I'm talking about, open up IORegistryExplorer or IOJones and hotplug a Thunderbolt device; you should see both the IOThunderboltPort (and a bunch of other types of related object, such as AppleThunderboltPCIUpAdapter etc.) and the IOPCIDevice (as well as the PCI2PCI bridges via which the Thunderbolt bus works) appear. (Alternatively you can use ioreg to take snapshots before and after the hotplug.)
So in summary, I would match IOThunderboltPort services, ignore any without a PCI path property, and look up the corresponding IOPCIDevice in the IO Registry for the ones that have it to get to the actual device.
Finally i figured out a way indeed to monitor Thunderbolt Connection. Thanks to the apple tech guy who pointed me out in a right direction.
Monitoring the I/O Registry for IOEthernetInterface entries. It’s relatively easy to filter out Thunderbolt networking (I’m not sure what the best option is, but an easy option is to look for “ThunderboltIP” in the “IOModel” property of the parent IOEthernetController). This was the response from one of the Tech guys from apple on Apple forum. Using the above info i wrote a piece of code which will return you the status of Thunderbolt port.
#include <IOKit/network/IOEthernetController.h>
- (void) monitorThunderboltConnection
{
CFMutableDictionaryRef matchingDict;
io_iterator_t iter;
io_object_t controllerService;
kern_return_t kr;
UInt8 MACAddress[kIOEthernetAddressSize];
QNInterfaceModel *interfaceModel = [[QNInterfaceModel alloc] initWithInterfaceModel];
/* set up a matching dictionary for the class */
matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
if (matchingDict == NULL)
{
NSLog(#"Failed");
return;
}
/* Now we have a dictionary, get an iterator.*/
kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
if (kr == kIOReturnSuccess)
{
// Actually iterate through the found devices.
io_registry_entry_t serviceObject;
while ((serviceObject = IOIteratorNext(iter)))
{
// Put this services object into a dictionary object.
kr = IORegistryEntryGetParentEntry(serviceObject,
kIOServicePlane,
&controllerService);
if (KERN_SUCCESS != kr)
{
printf("IORegistryEntryGetParentEntry returned 0x%08x\n", kr);
}
else
{
CFMutableDictionaryRef serviceDictionary;
CFTypeRef networkType;
CFTypeRef MACAddressAsCFData;
NSNumber *linkStatus;
if (IORegistryEntryCreateCFProperties(serviceObject,
&serviceDictionary,
kCFAllocatorDefault,
kNilOptions) == kIOReturnSuccess)
{
networkType = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOModel),
kCFAllocatorDefault,
0);
if(networkType)
{
if (CFGetTypeID(networkType) == CFStringGetTypeID())
{
CFStringRef networkName = networkType;
interfaceModel.interfaceName = (__bridge NSString *)networkName;
}
CFRelease(networkType);
}
if([interfaceModel.interfaceName isEqualToString:#"ThunderboltIP"])
{
MACAddressAsCFData = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0);
if (MACAddressAsCFData)
{
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr
// Get the raw bytes of the MAC address from the CFData
CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
if (KERN_SUCCESS != kr)
{
printf("GetMACAddress returned 0x%08x\n", kr);
}
else
{
interfaceModel.macAddress = [[NSString stringWithFormat:#"%02x:%02x:%02x:%02x:%02x:%02x",MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], MACAddress[4], MACAddress[5]] uppercaseString];
}
CFRelease(MACAddressAsCFData);
}
linkStatus = (__bridge NSNumber *)(IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOLinkStatus),
kCFAllocatorDefault,
0));
if (linkStatus)
{
NSLog(#"%#", [linkStatus stringValue]);
if([linkStatus integerValue] == 3) // Thunderbolt IP is Connnected
{
interfaceModel.connectedStatus = YES;
}
else
{
interfaceModel.connectedStatus = NO;
}
}
CFStringRef bsdName = ( CFStringRef ) IORegistryEntrySearchCFProperty (controllerService,
kIOServicePlane,
CFSTR ( kIOBSDNameKey ),
kCFAllocatorDefault,
kIORegistryIterateRecursively);
interfaceModel.interfaceName = (__bridge NSString *) bsdName;
if(interfaceModel.connectedStatus == YES)
{
NSLog(#"Connected");
}
else
{
NSLog(#"DisConnected");
}
}
// Failed to create a service dictionary, release and go on.
IOObjectRelease(serviceObject);
// Done with the parent Ethernet controller object so we release it.
(void) IOObjectRelease(controllerService);
continue;
}
}
}
}
/* Done, release the iterator */
IOObjectRelease(iter);
}
NOTE: I am using Interface model to collect all the thunderbolt info like Hardware Address, BSD Name, Link Status etc. You also need add I/O Kit framework to your project.
I'm trying to find a specific entry in my Mac OS X keychain, based on it's name (kSecAttrLabel), but it looks like SecItemCopyMatching is broken and applies no filtering whatsoever when looking for items of type: kSecClassIdentity.
This piece of code will return all identities found in all keychains, despite the kSecAttrLabel: #"MyIdentity" parameter:
NSDictionary *query = #{ (__bridge id)kSecClass: (__bridge NSString*)kSecClassIdentity,
(__bridge id)kSecAttrLabel: #"MyIdentity",
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll,
(__bridge id)kSecReturnAttributes: #YES,
(__bridge id)kSecReturnRef: #YES };
OSStatus status;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey);
Granted, I can then find the one identity I'm looking for by filtering manually the returned array, however, beside the fact that, IMHO, it should just work, I also would like to remove this identity from my keychain using SecItemDelete(), which takes a query as parameter, just like SecItemCopyMatching.
If filtering doesn't work for SecItemCopyMatching, then it is likely that it won't work for SecItemDelete and this mean I will simply erase the content of my keychain if I try to call SecItemDelete with this query.
What am I doing wrong?
I think I have just found a solution. It was suggested on on another forum that
Using labels on an identity is tricky because identities are not stored in the keychain as an atomic item but are store as a separate private key and certificate, and those items use labels in different ways.
This made me realise that a solution is to search for a certificate by label using SecItemCopyMatching, and then create the identity using SecIdentityCreateWithCertificate. The latter call should find the matching private key in the Keychain. Here is the full code (in C++) that seems to work for me on macOS Mojave:
SecIdentityRef identity = nullptr;
const char* certificateName = ...;
const void* keys[] = {
kSecClass,
kSecMatchLimit,
kSecReturnRef,
kSecAttrLabel
};
const void* values[] = {
kSecClassCertificate,
kSecMatchLimitOne,
kCFBooleanTrue,
CFStringCreateWithCString(nullptr, certificateName, kCFStringEncodingUTF8)
};
CFDictionaryRef query = CFDictionaryCreate(nullptr, keys, values, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFTypeRef result;
OSStatus status = SecItemCopyMatching(query, &result);
CFRelease(query);
CFRelease(values[3]);
if (status) {
// error
}
else {
SecCertificateRef certificate = (SecCertificateRef)result;
status = SecIdentityCreateWithCertificate(nullptr, certificate, &identity);
CFRelease(certificate);
if (status) {
// error
}
}
I had a similar problem, but I was using kSecAttrApplicationTag rather than kSecAttrLabel. I am not an objective c nor an IOS security expert by any means. It turns out the method I was using to create the lookup tag was incorrect. Here is what worked for me:
- (void) getOrCreateKey: (NSNumber*)bits publicIdentifier:(NSString*)publicID
// no! This appears in several samples, but did not work for me on iOS
// NSData * publicLookupTag = [NSData dataWithBytes:publicId length:strlen((const char *)publicId)];
//
// yes!
NSData * publicLookupTag = [NSData dataWithBytes:[publicId UTF8String] length:publicId.length];
NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
[queryPublicKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
[queryPublicKey setObject:publicLookupTag forKey:(id)kSecAttrApplicationTag];
[queryPublicKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
OSStatus lookupStatus = noErr;
lookupStatus = SecItemCopyMatching((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicLookupKey);
Am trying to get file extension of photos using the new Photos API in iOS 8 but haven't found a way to do so until now. Before iOS 8.0 I would use ALAssetRepresentation to get the file extension like:
// Get asset representation from asset
ALAssetRepresentation *assetRepresentation = [asset defaultRepresentation];
// Extract file extension from the original file name
NSString* fileExt = [[assetRepresentation filename] pathExtension];
Is there any way to get file extension of photos now?
PS: I am using new Photos API as I need to access all photos in my photos app, and ALassetsLibrary gives access to "Recently Added" photos only.
I've got it.
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:imageRequestOptions resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
NSLog(#"info - %#", info);
}];
PHImageFileDataKey = <PLXPCShMemData: 0x179ab6d0> bufferLength=1384448 dataLength=1384448;
PHImageFileOrientationKey = 1;
PHImageFileSandboxExtensionTokenKey = "c05e608acaf0bb212086ed2d512ccc97ea720ac3;00000000;00000000;0000001a;com.apple.app-sandbox.read;00000001;01000003;0000000000030b8c;/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG";
PHImageFileURLKey = "file:///var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG";
PHImageFileUTIKey = "public.jpeg";
PHImageResultDeliveredImageFormatKey = 9999;
PHImageResultIsDegradedKey = 0;
PHImageResultIsInCloudKey = 0;
PHImageResultIsPlaceholderKey = 0;
PHImageResultWantedImageFormatKey = 9999;
Here is one way to do it:
PHImageRequestOptions * imageRequestOptions = [[PHImageRequestOptions alloc] init];
imageRequestOptions.synchronous = YES;
[[PHImageManager defaultManager]
requestImageForAsset:asset
targetSize:CGSizeMake(2048, 2048)
contentMode:PHImageContentModeAspectFit
options:imageRequestOptions
resultHandler:^(UIImage *result, NSDictionary *info) {
}];
The file name is contained in info. For example:
PHImageFileURLKey = "file:///var/mobile/Media/DCIM/100APPLE/IMG_0066.JPG";
**imageManager.requestImageDataForAsset((images[indexPath.row] as PHAsset), options:PHImageRequestOptions(), resultHandler: {imagedata,dataUTI,Orientation,info in
var str:String=((((info as Dictionary)["PHImageFileURLKey"])! as NSURL).lastPathComponent as String)
cell.imageName.text=str as String**
These is also once simple way to get original file name selected from photos
PHAsset *asset; // Init this object with your PHAsset object
//and then use below line
NSLog(#"asset ext : %#",[[asset valueForKey:#"filename"] pathExtension]);
I've already searched "everything" about this in Google/Stackoverflow, but I'm still stuck. I have just started developing OSX Apps, so I'm a (almost) complete newbie in Objective-C and Xcode 5 (5.0.2).
All I need is a simple webview to load a webgame from a given URL. This webview must behave just like a very simple Safari browser. My app is already working relatively well. It loads the game OK, and after a lot of struggling I succeeded making it show javascript alerts and confirms.
THE POINT: I need to display a simple text message to the user, in case of no internet connection is detected, then I need to close the app. It seems a very trivial thing, but I can't find a way to do that!!
That's my appDelegate.M:
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize myWebView;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
// Check if there's internet connection:
#include <SystemConfiguration/SystemConfiguration.h>
static BOOL internetOk()
{
BOOL returnValue = NO;
struct sockaddr zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sa_len = sizeof(zeroAddress);
zeroAddress.sa_family = AF_INET;
SCNetworkReachabilityRef reachabilityRef = SCNetworkReachabilityCreateWithAddress(NULL, (const struct sockaddr*)&zeroAddress);
if (reachabilityRef != NULL)
{
SCNetworkReachabilityFlags flags = 0;
if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
BOOL isReachable = ((flags & kSCNetworkFlagsReachable) != 0);
BOOL connectionRequired = ((flags & kSCNetworkFlagsConnectionRequired) != 0);
returnValue = (isReachable && !connectionRequired) ? YES : NO;
}
CFRelease(reachabilityRef);
}
return returnValue;
}
// -
if(internetOk())
{
[self.window setContentView:self.myWebView];
[self.window toggleFullScreen:#""];
[self.myWebView setMainFrameURL:#"http://www.mywebgameurl.com"];
}
else
{
// SHOWS ERROR MESSAGE AND CLOSES APP! HOW CAN I DO IT????
}
}
#end
Any help is welcome, thanks!!
You're looking for the NSAlert class, check here for Apple's docs.
Sample usage:
NSAlert* alert = [NSAlert alertWithMessageText:#"Internet Error"
defaultButton:nil
alternateButton:nil
otherButton:nil
informativeTextWithFormat:#"No internet."];
[alert runModal];
Google gave me: http://developer.apple.com/samplecode/LoginItemsAE/index.html
And I figured there must be a better way than using AppleScript Events.
So I downloaded the Growl sources. They use the exact sources from that Apple developer article.
Is there a better way?
(I refer to Login Items in Accounts in System Preferences, ie. making my program start when the user Logs in, programmatically)
There's an API that's new in Leopard called LSSharedFileList. One of the things it lets you do is view and edit the Login Items list (called Session Login Items in that API).
BTW, I'm the lead developer of Growl. We haven't switched away from AE yet because we still require Tiger, but I'm thinking of dropping that for 1.2 (haven't talked it over with the other developers yet). When we do drop Tiger, we'll drop LoginItemsAE as well, and switch to the Shared File List API.
EDIT from the year 2012: Since 2009, when I originally wrote this answer, Growl has switched to LSSharedFileList and I've left the project.
I stumbled across Ben Clark-Robinson's LaunchAtLoginController. A very elegant solution to a very common problem.
This works on xcode 5.
- (BOOL)isLaunchAtStartup {
// See if the app is currently in LoginItems.
LSSharedFileListItemRef itemRef = [self itemRefInLoginItems];
// Store away that boolean.
BOOL isInList = itemRef != nil;
// Release the reference if it exists.
if (itemRef != nil) CFRelease(itemRef);
return isInList;
}
- (void)toggleLaunchAtStartup {
// Toggle the state.
BOOL shouldBeToggled = ![self isLaunchAtStartup];
// Get the LoginItems list.
LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginItemsRef == nil) return;
if (shouldBeToggled) {
// Add the app to the LoginItems list.
CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL);
if (itemRef) CFRelease(itemRef);
}
else {
// Remove the app from the LoginItems list.
LSSharedFileListItemRef itemRef = [self itemRefInLoginItems];
LSSharedFileListItemRemove(loginItemsRef,itemRef);
if (itemRef != nil) CFRelease(itemRef);
}
CFRelease(loginItemsRef);
}
- (LSSharedFileListItemRef)itemRefInLoginItems {
LSSharedFileListItemRef res = nil;
// Get the app's URL.
NSURL *bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
// Get the LoginItems list.
LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginItemsRef == nil) return nil;
// Iterate over the LoginItems.
NSArray *loginItems = (__bridge NSArray *)LSSharedFileListCopySnapshot(loginItemsRef, nil);
for (id item in loginItems) {
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)(item);
CFURLRef itemURLRef;
if (LSSharedFileListItemResolve(itemRef, 0, &itemURLRef, NULL) == noErr) {
// Again, use toll-free bridging.
NSURL *itemURL = (__bridge NSURL *)itemURLRef;
if ([itemURL isEqual:bundleURL]) {
res = itemRef;
break;
}
}
}
// Retain the LoginItem reference.
if (res != nil) CFRetain(res);
CFRelease(loginItemsRef);
CFRelease((__bridge CFTypeRef)(loginItems));
return res;
}
I do this in an app I'm writing:
Check out UKLoginItemRegistry for an easy way to do this pragmatically. Afaik, there is no way in Tiger to do this without Apple Events; in Leopard there's a better way, but if you use UKLoginItemRegistry it really is no problem. Here's the complete code for implementing an "Open at Logon" menu item
+ (bool)isAppSetToRunAtLogon {
int ret = [UKLoginItemRegistry indexForLoginItemWithPath:[[NSBundle mainBundle] bundlePath]];
NSLog(#"login item index = %i", ret);
return (ret >= 0);
}
- (IBAction)toggleOpenAtLogon:(id)sender {
if ([PopupController isAppSetToRunAtLogon]) {
[UKLoginItemRegistry removeLoginItemWithPath:[[NSBundle mainBundle] bundlePath]];
} else {
[UKLoginItemRegistry addLoginItemWithPath:[[NSBundle mainBundle] bundlePath] hideIt: NO];
}
}
I've refactored some of the answers here to provide a category on NSApplication that provides a launchAtLogin property.
https://gist.github.com/joerick/73670eba228c177bceb3
SMLoginItemSetEnabled is another modern option, see Modern Login Items article by Cory Bohon where he explains that you have to create a helper application whose sole purpose is to launch the main application. There's also a full step by step explanation in SMLoginItemSetEnabled - Start at Login with App Sandboxed on Stack Overflow.
Check here an open source example: https://github.com/invariant/rhpnotifier (LoginItem.m, LoginItem.h)