Under iOS7, is the primary ANCS Service meant to be constantly advertised, or does it need to be enabled in obfuscated settings / implemented using a custom CBPeripheralManager (using the Apple-specified Service and Characteristic UUIDs) for a potential Notification Consumer to successfully discover it and subscribe?
The Apple documentation (both the CoreBluetooth Programming Guide, and the ANCS Specification) are surprisingly bereft of any information on this. They seem to hint at requiring a custom implementation, but this is just conjecture on our part.
Given the primary ANCS Service UUID: 7905F431-B5CE-4E99-A40F-4B1E122D00D0, performing a scan yields no hits. Scanning the entire BLE spectrum, as expected, yields hits for other BLE devices, but not a single ANCS device.
EDIT 1:
Defining a custom CBPeripheralManager and manually adding the Apple-specified ANCS Service with its associated Characteristics fails, with the NSError: Error Domain=CBErrorDomain Code=8 "The specified UUID is not allowed for this operation."
Consequently, it appears that the Service UUID is reserved by Apple (as it should be), and we cannot enable it in this manner.
Any insight is greatly appreciated; we've reached out to Apple about this, and will update when we hear from them.
The code below reproduces the NSError mentioned above:
// define the ANCS Characteristics
CBUUID *notificationSourceUUID = [CBUUID UUIDWithString:#"9FBF120D-6301-42D9-8C58-25E699A21DBD"];
CBMutableCharacteristic *notificationSource = [[CBMutableCharacteristic alloc] initWithType:notificationSourceUUID properties:CBCharacteristicPropertyNotifyEncryptionRequired value:nil permissions:CBAttributePermissionsReadEncryptionRequired];
CBUUID *controlPointUUID = [CBUUID UUIDWithString:#"69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9"];
CBMutableCharacteristic *controlPoint = [[CBMutableCharacteristic alloc] initWithType:controlPointUUID properties:CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteEncryptionRequired];
CBUUID *dataSourceUUID = [CBUUID UUIDWithString:#"22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB"];
CBMutableCharacteristic *dataSource = [[CBMutableCharacteristic alloc] initWithType:dataSourceUUID properties:CBCharacteristicPropertyNotifyEncryptionRequired value:nil permissions:CBAttributePermissionsReadEncryptionRequired];
// define the ANCS Service
CBUUID *ANCSUUID = [CBUUID UUIDWithString:#"7905F431-B5CE-4E99-A40F-4B1E122D00D0"];
CBMutableService *ANCS = [[CBMutableService alloc] initWithType:ANCSUUID primary:YES];
ANCS.characteristics = #[notificationSource, controlPoint, dataSource];
// define the Advertisement data
NSMutableDictionary *advertisementData = [NSMutableDictionary dictionary];
[advertisementData setValue:#"CUSTOM_ANCS" forKey:CBAdvertisementDataLocalNameKey];
[advertisementData setValue:#"7905F431-B5CE-4E99-A40F-4B1E122D00D0" forKey:CBAdvertisementDataServiceUUIDsKey];
// publish the ANCS service
[self.peripheralManager addService:ANCS];
As a belated answer to this question, now that Mavericks is out, here is what we've come up with.
Our initial efforts to implement the ANCS specification between two iOS devices, one as Peripheral one as Central, were unsuccessful. Apple responded to us after some time (hat tip to their evangelists) and told us this was impossible.
With the addition of the CBPeripheralManager class and CBPeripheralManagerDelegate protocol to the CoreBluetooth.framework embedded in the IOBluetooth.framework on OSX Mavericks (deep breath), we can now use the BLE radio on an OSX device to implement and advertise ANCS.
Thus, this snippet belongs to a CBPeripheralManager on OSX:
- (void) advertiseANCS
{
NSLog(#"%s", __FUNCTION__);
// define the ANCS Characteristics
CBUUID *notificationSourceUUID = [CBUUID UUIDWithString:#"9FBF120D-6301-42D9-8C58-25E699A21DBD"];
CBMutableCharacteristic *notificationSource = [[CBMutableCharacteristic alloc] initWithType:notificationSourceUUID properties:CBCharacteristicPropertyNotifyEncryptionRequired value:nil permissions:CBAttributePermissionsReadEncryptionRequired];
CBUUID *controlPointUUID = [CBUUID UUIDWithString:#"69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9"];
CBMutableCharacteristic *controlPoint = [[CBMutableCharacteristic alloc] initWithType:controlPointUUID properties:CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteEncryptionRequired];
CBUUID *dataSourceUUID = [CBUUID UUIDWithString:#"22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB"];
CBMutableCharacteristic *dataSource = [[CBMutableCharacteristic alloc] initWithType:dataSourceUUID properties:CBCharacteristicPropertyNotifyEncryptionRequired value:nil permissions:CBAttributePermissionsReadEncryptionRequired];
// define the ANCS Service
CBUUID *ANCSUUID = [CBUUID UUIDWithString:#"7905F431-B5CE-4E99-A40F-4B1E122D00D0"];
CBMutableService *ANCS = [[CBMutableService alloc] initWithType:ANCSUUID primary:YES];
ANCS.characteristics = #[notificationSource, controlPoint, dataSource];
// define the Advertisement data
NSMutableDictionary *advertisementData = [NSMutableDictionary dictionary];
[advertisementData setValue:#"ANCS" forKey:CBAdvertisementDataLocalNameKey];
[advertisementData setValue:#[ANCSUUID] forKey:CBAdvertisementDataServiceUUIDsKey];
// publish the ANCS service
[self.peripheralManager addService:ANCS];
[self.peripheralManager startAdvertising:advertisementData];
}
Whereas this snippet belongs on a CBCentralManager on an iOS device:
- (void) discoverANCS
{
NSLog(#"%s", __FUNCTION__);
NSMutableArray *services = [NSMutableArray array];
[services addObject:#"7905F431-B5CE-4E99-A40F-4B1E122D00D0"];
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setValue:[NSNumber numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
[self.centralManager scanForPeripheralsWithServices:services options:options];
}
The iOS device can now see and connect to the OSX radio, which implements the ANCS specification as detailed in the Apple documentation.
<CBCentralManager: 0x14e23280> <CBPeripheral: 0x14d27b40 identifier = 7231B80F-874E-DB5F-2AF9-7F376911E2B7, Name = "ANCS", state = disconnected> {
kCBAdvDataChannel = 39;
kCBAdvDataIsConnectable = 1;
kCBAdvDataLocalName = ANCS;
} -60
Happy hunting
Well the reason is because you are setting the UUID for the advertisement Data Dictionary as a String and not as a CBUUID, also I think that key takes an array of CBUUIDs.
therefore this should make it work:
NSDictionary *advertisementData = #{
CBAdvertisementDataServiceUUIDsKey:#[[CBUUID UUIDWithString:#"7905F431-B5CE-4E99-A40F-4B1E122D00D0"]],
CBAdvertisementDataLocalNameKey:#"ANCS",
};
EDIT: Oh yeah my bad! I forgot to mention that if you are trying to discover this ANCS service from another iOS Device you wont be able to see it, not under iOS 7. Somehow the OS is reserving that service to itself and wont show up on your didDiscoverServices callback even though you might be seeing it on your advertisement data. It will however, work if you have an external device, like a non-iOS device, or a pebble-like device. This is how you expose the ANCS functionality but the rest of the implementation is up to consumer of the service.
According to this blog post:
http://blog.punchthrough.com/post/63658238857/the-apple-notification-center-service-or-wtf-is
You can advertise with 'service solicitation' to pair and access the ANCS without writing any code on the iPhone!
I have not tried it, but will soon.
For anyone currently Googling a similar question: ANCS via CoreBluetooth appears to no longer work in iOS 9. Specifically,
This functionality was removed from OS X and iOS.
Neither platform can be used to consume the ANCS service anymore using CoreBluetooth.
Given by https://forums.developer.apple.com/thread/24336
The ANCS is not advertised on iOS, I used a following way to achieve a long time connection with ANCS:
My peripheral device uses a dummy service, which is advertised. An iOS application is used to discover a device with this service and to create a connection. You can write your own application, or use one of free available (like LightBlue for example).
Once a connection is established, the peripheral device enumerates all services present on connected iOS device. Beside of others, there are those three mentioned in ANCS documentation.
If your register notifications for them, you will get ANCS data.
If you bond devices (iOS and peripheral), ANCS will automatically care for connection (re)establishment any time, if it found bonded device being advertised.
I use ANCS without any code on the iPhone using "pebble-like" prototype hardware.
Using the methods documented above on this question.
The video is for a kind of joke show and meant as a joke as is the concept of "area-wide notifications" :-) and not at all technical. But might be informative somewhat.
http://www.youtube.com/watch?v=O-YWMl7IS-g
I don't make money from my youtube BTW
I have not been successful with iOS--iOS attempts.
Related
What is the best way to programmatically change the order of "preferred" networks in OS X? Objective-C preferred...
I can use CoreWLAN to gather the list, and even add to it, but as far as re-ordering I am at a loss. I can create a copy of the preference file, edit it and change the order of precedence, and then use a bash script to write over the existing configuration, but that seems a but messy.
I am aware of the networksetup -addpreferredwirelessnetworkatindex command, but it does not work correctly in 10.10 (works fine for 10.9 systems) - it adds but does not set order properly.
SystemConfiguration framework? Something else?
Thanks!
I was looking for a way to accomplish this after transitioning a user from an open wireless network to a WPA2E network using EAP-TTLS. Since the user connects to the open network first, it remains higher in the Preferred Networks list.
Here is what I came up with:
CWInterface *interface = [CWInterface interfaceWithName:[
[CWInterface interfaceNames] anyObject]
];
CWMutableConfiguration *config = [CWMutableConfiguration
configurationWithConfiguration:interface.configuration
];
NSMutableArray *networks = [NSMutableArray arrayWithArray:
[config.networkProfiles array]
];
//Remove URI_Open (if present) and
//move URI_Secure (if present) to index 0
for (CWNetworkProfile *profile in [networks copy]) {
if ([[profile ssid] isEqualToString:#"URI_Secure"]) {
[networks removeObject:profile];
} else if ([[profile ssid] isEqualToString:#"URI_Open"]) {
CWNetworkProfile *tmp = profile;
[networks removeObject:tmp];
[networks insertObject:tmp atIndex:0];
}
}
config.networkProfiles = [NSOrderedSet orderedSetWithArray:networks];
SFAuthorization *auth = [SFAuthorization authorization];
BOOL authResult = [auth obtainWithRight:"system.preferences"
flags:(
kAuthorizationFlagExtendRights |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize
) error:nil
];
NSError *error = nil;
[interface commitConfiguration:config authorization:auth error:&error];
Some notes/disclaimers:
I do not use OS X regularly. I have one test Mac in my office. It has 10.7.5 installed.
This is the first thing I have ever written in Objective-C. It is the result of a single afternoon; as such it is probably broken and ugly. YMMV.
Question specified 10.10. I used interfaceWithName and interfaceNames, which are deprecated in 10.10. I am not sure what the proper replacement is, but I suspect CWWifiClient.
My approach was based loosely on this ruby program.
I removed error handling for brevity.
I did look into using networksetup or removing the open network right in the .mobileconfig, but neither seemed to work quite right.
Since I just pull the network profile list out into a mutable array, this is easily adaptable to any arbitrary sorting etc.
I am seeing that you can launch FaceTime from your app via
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"facetime://tel-number"]];
I am also reading that since there is no officially public FaceTime API apple will reject you.
Does anyone know if this rejection talk is true? PAIR has this feature and they have never been rejected.
This is now documented and legal:
https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/FacetimeLinks/FacetimeLinks.html#//apple_ref/doc/uid/TP40007899-CH2-SW1
My app got rejected for using FaceTime url. This is the part of response i got from Apple in resolution center.
We found the following non-public API/s in your app: Specifically,
your app uses the FaceTime URL scheme, which is undocumented.
If you have defined methods in your source code with the same names as
the above-mentioned APIs, we suggest altering your method names so
that they no longer collide with Apple's private APIs to avoid your
application being flagged in future submissions.
It was an update of a previous release. The first version got accepted without any problem. Now the update has been rejected due to the above mentioned reason. Seems i have to publish the app without the FaceTime thingy now.
Edit:
Its now legal to use FaceTime url in third party apps.
As a general rule, if you use undocumented API calls and apple catches you, they will reject your application. The reason is because they could change the API call that you are using in new IOS updates and thus would cause your application to crash or not work properly. You can try and submit using the undocumented API and hope that apple lets it through but as i said, you run the risk of Apple changing this api call or removing it completely from the OS in the future.
I don't see any reason this would be rejected, especially if there's already an app that uses this functionality. The App Store Review Guidelines are the best way to determine if your app will be rejected, and I don't see anything in there that applies to you situation.
Of course, Apple can do whatever they want, so the only way to be absolutely sure it will be accepted is to submit it, but I highly doubt you will have a problem.
It is official that you can use Native app URL strings for FaceTime video calls:
facetime:// 14085551234
facetime://user#example.com
Please refer to the link: https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/FacetimeLinks/FacetimeLinks.html
Though this feature is supported on all devices, you have to change the code a little bit for iOS 10.0 and above as openURL(_:) is deprecated.
https://developer.apple.com/documentation/uikit/uiapplication/1622961-openurl?language=objc
Please refer code below for the current and fallback mechanism, so this way it will not get rejected by Appstore.
-(void) callFaceTime : (NSString *) contactNumber
{
NSURL *URL = [NSURL URLWithString:[NSString
stringWithFormat:#"facetime://%#", contactNumber]];
if (#available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:URL options:#{}
completionHandler:^(BOOL success)
{
if (success)
{
NSLog(#"inside success");
}
else
{
NSLog(#"error");
}
}];
}
else {
// Fallback on earlier versions
NSString *faceTimeUrlScheme = [#"facetime://"
stringByAppendingString:contactNumber];
NSURL *facetimeURL = [NSURL URLWithString:faceTimeUrlScheme];
// Facetime is available or not
if ([[UIApplication sharedApplication] canOpenURL:facetimeURL])
{
[[UIApplication sharedApplication] openURL:facetimeURL];
}
else
{
// Facetime not available
NSLog(#"Facetime not available");
}
}
}
in contactNumber either pass phone number or appleid.
NSString *phoneNumber = #"9999999999";
NSString *appleId = #"abc#gmail.com";
[self callFaceTime:appleId];
objective-c ios
Using the new Facebook SDK 3.1 and iOS 6 there are 2 (actually 3) ways to post.
(Seems the new trend is to have more options to make it more simple??) OMG!!
Here is one:
SLComposeViewController *fbPost = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[fbPost addURL:[NSURL URLWithString:href]];
[self presentViewController:fbPost animated:YES completion:nil];
And this is another way using native dialogs:
[FBNativeDialogs presentShareDialogModallyFrom:self
initialText: nil
image: nil
url: [NSURL URLWithString:href]
handler:^(FBNativeDialogResult result, NSError *error) {
if (error) {
}
else
{
switch (result) {
case FBNativeDialogResultSucceeded:
break;
case FBNativeDialogResultCancelled:
break;
case FBNativeDialogResultError:
break;
}
}
}];
We, developers, think this is cool because we give a nice functionality to the user and also because our app name appears in the post and that can make some promotion of the app.
The funny thing is that latest implementations are not allowing to specify the app name was posting, the name appears after 'via'.
I tried aswell using SLRequest:
ACAccountStore *store = [[ACAccountStore alloc] init];
ACAccountType *fbType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
(options)[#"ACFacebookAppIdKey"] = kFacebookAppID;
(options)[#"ACFacebookPermissionsKey"] = #[#"publish_stream"];
(options)[#"ACFacebookAudienceKey"] = ACFacebookAudienceFriends;
[store requestAccessToAccountsWithType:fbType options:options completion:^(BOOL granted, NSError *error) {
if(granted) {
// Get the list of Twitter accounts.
NSArray *fbAccounts = [store accountsWithAccountType:fbType];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
(params)[#"link"] = href;
// (params)[#"picture"] = picture;
// (params)[#"name"] = name;
(params)[#"actions"] = #"{\"name\": \"Go Gabi\", \"link\": \"http://www.gogogabi.com\"}";
//Set twitter API call
SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodPOST
URL:[NSURL URLWithString:#"https://www.facebook.com/dialog/feed"] parameters:params];
//Set account
[postRequest setAccount: [fbAccounts lastObject]];
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if(error)
{
NSLog(#"%#", error.description);
}
else
{
NSLog(#"%#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
}
}];
} else {
}
}];
Unfortunatelly to share that name is not so trivial anymore, I wonder why and who was designing the new implementation...
I would appreciate to get some help on that, thanks in advance.
I try to make my questions funny because is soo boring spend time in so trivial topics...
When you use the SLComposeViewController, it's actually the system presenting to you their controller, and it's the user who sends using the post button. Therefore on Facebook it appears as "via iOS".
There's no way to change that.
Using the Facebook SDK 3.1, under the hood it is also using the iOS 6 native integration, so when you're calling the FBNativeDialogs, on iOS 6, it's using SLComposeViewController.
Facebook continued to develop their SDK because they provide a couple of nice modules to use "out of the box" - this includes friends list selector etc... But I believe the biggest reason for Facebook to continue supporting their SDK it for backward compatibility. Under the hood if you're not on iOS 6, it falls back to it's library, and if you are on iOS 6, it uses the system integration.
Facebook is a big thing, and now it's natively available a lot of developers will be using it, just like Twitter's integration last year. The problem of course is at that point the developer has the option to drop older iOS support, or... have a lot of duplicate code, in the sense that they will check for SLComposeViewController and if it's not available (iOS 5) then use the old Facebook SDK... You can imagine how this would become very messy very quickly.
So, the Facebook SDK (3.1) is using iOS system Facebook integration if available, or if not, it's own. In a nutshell, unless you really want the Facebook SDK goodies (friend picket to name one), and you're not planning on supporting iOS < 6 then you don't need to worry about their SDK, just use the Social framework.
So, back to your question, there are 3 ways to post to Facebook ? Actually taking into consideration what I mentioned, there are 2 ways in iOS 6: SLComposeViewController or, SLRequest. On older iOS versions, only 1: Facebook SDK.
Since the SLComposeViewController is owned by the system, not your app, it will always share as "via iOS".
On the other hand SLRequest will show your apps name. When you specify an account for your SLRequest, that account was acquired via the ACAccountStore as a result of passing in some options including ACFacebookAppIdKey, which will be used to determine your Facebook apps name to post onto the users feed as part of the post.
Hope this helps.
I'm writing an OS X application that depends on the ability to determine wireless signal strength, but I can't figure out what entitlements to use to sandbox it.
Whenever I use
NSMutableArray *scanResults;
CWInterface *currentInterface = [CWInterface interface];
NSLog(#"currInterface: %#\n", currentInterface);
NSMutableDictionary *signalsDict = [[NSMutableDictionary alloc] init];
NSError *err = nil;
scanResults = [NSMutableSet setWithSet:[currentInterface scanForNetworksWithSSID:nil error:&err]];
I get the error The operation couldn't be completed. (com.apple.coreWLAN.error error 1.) despite having all entitlements checked in XCode. What entitlement(s) am I missing?
The CoreWLANWirelessManager sample project has the same problem.
CoreWLAN doesn't seem to be available at all to sandboxed apps.
Apple's developer documentation states "With App Sandbox, your app cannot modify the system’s network configuration (whether with the System Configuration framework, the CoreWLAN framework, or other similar APIs)", which seems to imply that reading but not writing settings might be OK, but that doesn't seem to work in practice, and this is confirmed by a post by Apple DTS: https://forums.developer.apple.com/thread/11307
How about the entitlements for the Wifi Diagnostics app that ships with Mac OS X 10.11.1, located at /System/Library/CoreServices/Applications/. Checking entitlements I see that it posseses the following: com.apple.wifi.associate, com.apple.wifi.scan, com.apple.wifi.set_channel, com.apple.wifi.start_autojoin, com.apple.wireless-diagnostics, and com.apple.wireless-diagnostics.basic_report.
Are we mere mortals working in a sandbox not able to get these?
I think you need to check Outgoing Connections (Client).
You might want to use Apple80211 private framework by using dlfcn.h library. An iphone example can be found here:
http://www.csse.uwa.edu.au/~chris/iphone/APlogger/
Download the source file and investigate scanner module.
In summary, you will come up with something like this:
#define IF_NAME "en0"
#include <dlfcn.h>
- (void)performScan
{
int (*open)(void *);
int (*bind)(void *, NSString *);
int (*close)(void *);
int (*scan)(void *, NSArray **, void *);
void *libHandle;
void *airportHandle;
libHandle = dlopen("/System/Library/Frameworks/Preferences.framework/Preferences", RTLD_LAZY);
open = dlsym(libHandle, "Apple80211Open");
bind = dlsym(libHandle, "Apple80211BindToInterface");
scan = dlsym(libHandle, "Apple80211Scan");
close = dlsym(libHandle, "Apple80211Close");
open(&airportHandle);
bind(airportHandle, #IF_NAME);
NSArray *found;
NSDictionary *params = [[NSDictionary alloc] init];
scan(airportHandle, &found, params);
int nnw = [found count];
for(int i=0 ; i < nnw ; i++) {
NSDictionary *nw = [found objectAtIndex:i];
NSString *ssid = [self fixSSID:nw];
// RSSI indicates signal strength
int rssi = [[nw objectForKey:#"RSSI"] intValue];
}
// Cleanup
close(airportHandle);
dlclose(libHandle);
}
-(NSString *)fixSSID:(NSDictionary *)nw
{
if ([[nw objectForKey:#"HIDDEN_NETWORK"] boolValue])
return #"<hidden>";
else
return [nw objectForKey:#"SSID_STR"];
}
Note that if you use private frameworks in your iOS apps, you will not be able to publish them on App Store (Apple will reject your app because there is no public documentation for Apple80211 framework). but since your question is regarding OSX development, this doesn't apply for your case.
Hope it helps.
Is there a way (some API) to get the list of installed apps on an iPhone device.
While searching for similar questions, I found some thing related to url registration, but I think there must be some API to do this, as I don't want to do any thing with the app, I just want the list.
No, apps are sandboxed and Apple-accepted APIs do not include anything that would let you do that.
You can, however, test whether a certain app is installed:
if the app is known to handle URLs of a certain type
by using [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"thisapp://foo"]
You can get a list of apps and URL schemes from here.
For jailbroken devices you can use next snipped of code:
-(void)appInstalledList
{
static NSString* const path = #"/private/var/mobile/Library/Caches/com.apple.mobile.installation.plist";
NSDictionary *cacheDict = nil;
BOOL isDir = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] && !isDir)
{
cacheDict = [NSDictionary dictionaryWithContentsOfFile: path];
NSDictionary *system = [cacheDict objectForKey: #"System"]; // First check all system (jailbroken) apps
for (NSString *key in system)
{
NSLog(#"%#",key);
}
NSDictionary *user = [cacheDict objectForKey: #"User"]; // Then all the user (App Store /var/mobile/Applications) apps
for (NSString *key in user)
{
NSLog(#"%#",key);
}
return;
}
NSLog(#"can not find installed app plist");
}
for non jailbroken device, we can use third party framework which is called "ihaspp", also its free and apple accepted. Also they given good documentation how to integrate and how to use. May be this would be helpful to you. Good luck!!
https://github.com/danielamitay/iHasApp
You could do this by using the following:
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector = NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSMutableArray *Allapps = [workspace performSelector:selectorALL];
NSLog(#"apps: %#", Allapps);
And then by accessing each element and splitting it you can get your app name, and even the Bundle Identifier, too.
Well, not sure if this was available back when the last answer was given or not (Prior to iOS 6)
Also this one is time intensive, yet simple:
Go into settings > Gen. >usage. The first category under usage at least right now is Storage.
It will show a partial list of apps. At the bottom of this partial list is a button that says "show all apps".
Tap that and you'll have to go through screen by screen, and take screenshots (Quick lock button and home button takes a screenshot).
I'm doing this now and I have hundreds of apps on my iPhone. So it's going to take me a while. But at least at the end of the process I'll have Images of all my apps.