I am creating a cordova plugin to upload images to s3.
When I build the project I get the following error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method.'
I have followed other answers on here and added the extra keys to the info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIcons~ipad</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>icon-small</string>
<string>icon-40</string>
<string>icon-50</string>
<string>icon-76</string>
<string>icon-72</string>
<string>icon</string>
</array>
</dict>
</dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.28.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.0.1</string>
<key>Fabric</key>
<dict>
<key>APIKey</key>
<string></string>
<key>Kits</key>
<array>
<dict>
<key>KitInfo</key>
<dict/>
<key>KitName</key>
<string>Crashlytics</string>
</dict>
</array>
</dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>DynamoDBObjectMapper</key>
<dict>
<key>Default</key>
<dict>
<key>Region</key>
<string>eu-west-1</string>
</dict>
</dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>amazonaws.com</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>amazonaws.com.cn</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSLocationUsageDescription</key>
<string>Geolocation information is used to tag assessments and assessment contents with the users location. This is only used when conducting an assessment.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Geolocation information is used to tag assessments and assessment contents with the users location. This is only used when conducting an assessment.</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarHidden~ipad</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>AWS</key>
<dict>
<key>S3TransferManager</key>
<dict>
<key>Default</key>
<dict>
<key>Region</key>
<string>eu-west-1</string>
</dict>
</dict>
</dict>
</dict>
</plist>
This is the function in the plugin.
- (void)uploadImage:(CDVInvokedUrlCommand*)command
{
AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
NSString* filePath = [command argumentAtIndex:0 withDefault:nil];
NSURL *uploadingFileURL = [NSURL fileURLWithPath: filePath];
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.bucket = #"my-test-bucket";
uploadRequest.key = #"mykey";
uploadRequest.body = uploadingFileURL;
[[transferManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor]
withBlock:^id(AWSTask *task) {
if (task.error) {
if ([task.error.domain isEqualToString:AWSS3TransferManagerErrorDomain]) {
switch (task.error.code) {
case AWSS3TransferManagerErrorCancelled:
case AWSS3TransferManagerErrorPaused:
break;
default:
NSLog(#"Error: %#", task.error);
break;
}
} else {
// Unknown error.
NSLog(#"Error: %#", task.error);
}
}
if (task.result) {
AWSS3TransferManagerUploadOutput *uploadOutput = task.result;
// The file uploaded successfully.
}
return nil;
}];
}
The exception is thrown at line:
AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
I found a solution using the answer provided in https://stackoverflow.com/a/39957439/3191747
Adding the following to didFinishLaunchingWithOptions in the AppDelegate solved the problem:
AWSStaticCredentialsProvider *credentialsProvider = [[AWSStaticCredentialsProvider alloc] initWithAccessKey:AWS_ACCESS_KEY secretKey:AWS_SECRET_KEY];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionAPSoutheast1
credentialsProvider:credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
Related
i am trying to fetch two arrays against two keys in my Info.plist but instead not getting any data in my output. here is my code.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0),^{
NSString *post = [NSString stringWithFormat:#"URL"];
NSDictionary *dTmp = [[NSDictionary alloc] initWithContentsOfURL:[NSURL URLWithString:post]];
NSMutableArray *OriginalDetailsArray=[dTmp valueForKey:#"Objects"];
NSMutableArray *OriginalGalleryArray=[dTmp valueForKey:#"gallery"];
detailsArray=[[NSMutableArray alloc] init];
[detailsArray addObjectsFromArray:OriginalDetailsArray];
galleryArray=[[NSMutableArray alloc] init];
[galleryArray addObjectsFromArray:OriginalGalleryArray];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%#, %#",detailsArray, galleryArray);
});
});
Out Put is: You can see there is nothing in the output just empty brackets.
(
), (
)
here is my Info.plist file. if i remove second array "Gallery" and i only let "Objects" data fetches perfectly. But after adding Second Array it gives empty output.
<plist version="1.0">
<dict>
<key>Objects</key>
<array>
<dict>
<key>propid</key>
<integer>233</integer>
<key>title</key>
<string>101 Perthshire Private</string>
<key>type</key>
<string>For Sale</string>
<key>price</key>
<string>$899,900</string>
<key>bed</key>
<string>2</string>
<key>bath</key>
<string>3</string>
</dict>
</array>
</dict>
<dict>
<key>gallery</key>
<array>
<dict>
<key>imageurl</key>
<string>
/images/23330.jpg
</string>
</dict>
<dict>
<key>imageurl</key>
<string>
/images/23333.jpg
</string>
</dict>
<dict>
<key>imageurl</key>
<string>
/images/23339.jpg
</string>
</dict>
</array>
</dict>
</plist>
Your plist data formot are wrong. Please put below code on your php file and check it.
<plist version="1.0">
<dict>
<key>Objects</key>
<array>
<dict>
<key>propid</key>
<integer>233</integer>
<key>title</key>
<string>101 Perthshire Private</string>
<key>type</key>
<string>For Sale</string>
<key>price</key>
<string>$899,900</string>
<key>bed</key>
<string>2</string>
<key>bath</key>
<string>3</string>
</dict>
</array>
<key>gallery</key>
<array>
<dict>
<key>imageurl</key>
<string>/images/23330.jpg</string>
</dict>
<dict>
<key>imageurl</key>
<string>/images/23333.jpg</string>
</dict>
<dict>
<key>imageurl</key>
<string>/images/23339.jpg
</string>
</dict>
</array>
</dict>
</plist>
Please Try Below Code, I got Result.
NSArray *arrayObjects = [NSArray arrayWithArray:[dictRoot objectForKey:#"Objects"]];
NSArray *arrayGallery = [NSArray arrayWithArray:[dictRoot objectForKey:#"gallery"]];
NSLog(#"%#",arrayObjects);
NSLog(#"%#",arrayGallery);
i try and combine my dictionaries but to be honest i have no idea how. i try like thus, but two overtake one. sorry for the bad english.
[dict addEntriesFromDictionary:dict2];
1
<plist version="1.0">
<dict>
<key>Main</key>
<dict>
<key>DataStorage1</key>
<dict>
<key>A</key>
<string></string>
<key>B</key>
<string></string>
<key>C</key>
<string></string>
</dict>
</dict>
</dict>
</plist>
2
<plist version="1.0">
<dict>
<key>Main</key>
<dict>
<key>DataStorage2</key>
<dict>
<key>A</key>
<string></string>
<key>B</key>
<string></string>
<key>C</key>
<string></string>
</dict>
</dict>
</dict>
</plist>
I would like to make:
<plist version="1.0">
<dict>
<key>Main</key>
<dict>
<key>DataStorage1</key>
<dict>
<key>A</key>
<string></string>
<key>B</key>
<string></string>
<key>C</key>
<string></string>
</dict>
<key>DataStorage2</key>
<dict>
<key>A</key>
<string></string>
<key>B</key>
<string></string>
<key>C</key>
<string></string>
</dict>
</dict>
</dict>
I tried, but it never combined correctly.
Both dict and dict2 have one one key-value pair with the common key "Main".
Therefore
[dict addEntriesFromDictionary:dict2];
replaces the entire "Main" dictionary in dict with the value from dict2.
What you probably want is
[dict[#"Main"] addEntriesFromDictionary:dict2[#"Main"]];
to add the key-values pairs from the "Main" dictionary in dict2 to the "Main"
dictionary in dict. (This assumes that the "Main" dictionary in dict
is mutable.)
Example:
NSURL *url1 = [[NSBundle mainBundle] URLForResource:#"plist1" withExtension:#"plist"];
NSURL *url2 = [[NSBundle mainBundle] URLForResource:#"plist2" withExtension:#"plist"];
NSMutableDictionary *dict1 = [NSMutableDictionary dictionaryWithContentsOfURL:url1];
NSMutableDictionary *dict2 = [NSMutableDictionary dictionaryWithContentsOfURL:url2];
[dict1[#"Main"] addEntriesFromDictionary:dict2[#"Main"]];
I'm in a bit over my head here (a lot actually). I have a JSON response that's been converted to an NSDictionary. It's a mess of nested arrays and dictionaries within dictionaries within arrays, etc... I have no clue what to do with it. What I would like to do is make a simple NSDictionary for each "item" and use the properties to drive a UITableView. I don't know how to access objects several levels down. I've done a bit of searching and i see there's several ways to go about it (fast enumeration, blocks, etc..) but before I start spinning my wheels I'd love to know what would be best for my particular situation. I saved the NSDictionary as a plist for readability. I'll post it here:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>search_result</key>
<dict>
<key>latitude</key>
<string>51.508129</string>
<key>longitude</key>
<string>-0.128005</string>
<key>page</key>
<string>1</string>
<key>per_page</key>
<integer>3</integer>
<key>results</key>
<array>
<dict>
<key>result</key>
<dict>
<key>description_short</key>
<string>Experience the history and mystery of the most famous sites in the South of England!</string>
<key>flex_reference</key>
<string>FLX-LON-77B-D2F-5ED5</string>
<key>geocoded_latitude</key>
<string>51.5081289</string>
<key>geocoded_longitude</key>
<string>-0.128005</string>
<key>name</key>
<string>Stonehenge, Glastonbury, Avebury and Chalice Well</string>
<key>primary_image</key>
<string>http://media.****.com/FLX-LON-77B-D2F-5ED5-image_original-56.jpg</string>
<key>product_categories</key>
<array>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>type</string>
<key>name</key>
<string>Sightseeing Tours</string>
</dict>
</dict>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>category</string>
<key>name</key>
<string>Excursion</string>
</dict>
</dict>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>type</string>
<key>name</key>
<string>Attractions</string>
</dict>
</dict>
</array>
</dict>
</dict>
<dict>
<key>result</key>
<dict>
<key>description_short</key>
<string>Experience some of the most famous landmarks in English history, University City of Oxford, rolling countryside and honey stoned cottages of the Cotswolds and Stratford upon Avon home of the famous English plyright, William Shakespeare.</string>
<key>flex_reference</key>
<string>FLX-LON-2AD-267-38AB</string>
<key>geocoded_latitude</key>
<string>51.5081289</string>
<key>geocoded_longitude</key>
<string>-0.128005</string>
<key>name</key>
<string>Oxford, Stratford and the Cotswolds Villages</string>
<key>primary_image</key>
<string>http://media.*****.com/FLX-LON-2AD-267-38AB-image_original-AF.jpg</string>
<key>product_categories</key>
<array>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>type</string>
<key>name</key>
<string>Sightseeing Tours</string>
</dict>
</dict>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>category</string>
<key>name</key>
<string>Excursion</string>
</dict>
</dict>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>type</string>
<key>name</key>
<string>Attractions</string>
</dict>
</dict>
</array>
</dict>
</dict>
<dict>
<key>result</key>
<dict>
<key>description_short</key>
<string>The must see attractions of the United Kingdom, World Heritage sites, Stonehenge and the Roman Baths.</string>
<key>flex_reference</key>
<string>FLX-LON-65D-AC0-B08E</string>
<key>geocoded_latitude</key>
<string>51.5081289</string>
<key>geocoded_longitude</key>
<string>-0.128005</string>
<key>name</key>
<string>Stonehenge and Bath</string>
<key>primary_image</key>
<string>http://media.****.com/FLX-LON-65D-AC0-B08E-image_original-2E.jpg</string>
<key>product_categories</key>
<array>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>type</string>
<key>name</key>
<string>Sightseeing Tours</string>
</dict>
</dict>
<dict>
<key>product_category</key>
<dict>
<key>kind</key>
<string>category</string>
<key>name</key>
<string>Excursion</string>
</dict>
</dict>
</array>
</dict>
</dict>
</array>
<key>total_pages</key>
<integer>18</integer>
<key>total_results</key>
<integer>54</integer>
</dict>
</dict>
</plist>
NSDictionary *jsonResponse = /* get your dictionary from wherever */
NSDictionary *searchResults = [jsonResponse objectForKey:#"search_result"];
NSArray *allResults = [searchResults objectForKey:#"results"];
for (NSDictionary *result in allResults)
{
NSDictionary *resultDetails = [result objectForKey:#"result"];
NSString *name = [resultDetails objectForKey:#"name"];
NSURL *imageURL = [NSURL URLWithString:[resultDetails objectForKey:#"primary_image"]];
NSLog(#"Name: %#\n URL: %#", name, imageURL);
}
Retrieve the dictionary:
NSDictionary* dict= jsonDict[#"search_results"];
The value for key "results" is an array:
NSArray* results = dict[#"results"];
At the first index there is a dictionary:
NSDictionary* dict2= results[0];
For the key "result" there is another dictionary:
NSDictionary* dict3= dict2[#"result"];
From this dictionary you can retrieve the values that you want:
NSString* name= dict3[#"name"];
NSString* primaryImage= dict3[#"primary_image"];
No matter how many dicts and arrays you have, you can read one then you can read them all.To do this easier just think like they' re packets inside packets, and draw a graph with the objects.
EDIT
I didn't specify what dict was, added it.
I am just starting to work with preference files and I started having problems immediately when editing the root.plist in my settings bundle. My XCode 4 crashes every time I add a property to the plist while editing it as a property list. So I thought I would simply edit as source code. It seems to be a lot easier.
But when I run the program, the root.plist is not being read. (It was working fine with a settings bundle from a demo program. I'm using InAppSettingsKit.) I looked at the root.plist in the source code editor and it looks right. I tried to look at it as a property list and I get an error that says the plist is corrupted.
Here is the contents of my plist. Can someone tell me what is wrong with it?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<!-- Databases -->
<dict>
<key>Title</key> <string>Databases</string>
<key>Type</key> <string>PSGroupSpecifier</string>
</dict>
<dict>
<key>Type</key> <string>PSToggleSwitchSpecifier</string>
<key>Title</key> <string>db0</string>
<key>Key</key> <string>db0_preference</string>
<key>DefaultValue</key> <true/>
</dict>
<dict>
<key>Type</key> <string>PSToggleSwitchSpecifier</string>
<key>Title</key> <string>db1</string>
<key>Key</key> <string>db1_preference</string>
<key>DefaultValue</key> <true/>
</dict>
<!-- Sharing Actions -->
<dict>
<key>Type</key> <string>PSGroupSpecifier</string>
<key>Title</key> <string>Sharing Actions</string>
</dict>
<dict>
<key>Type</key> <string>PSToggleSwitchSpecifier</string>
<key>Title</key> <string>Facebook</string>
<key>Key</key> <string>facebook_preference</string>
<key>DefaultValue</key> <true/>
</dict>
<dict>
<key>Type</key> <string>PSToggleSwitchSpecifier</string>
<key>Title</key> <string>Twitter</string>
<key>Key</key> <string>twitter_preference</string>
<key>DefaultValue</key> <true/>
</dict>
<dict>
<key>Type</key> <string>PSToggleSwitchSpecifier</string>
<key>Title</key> <string>Email</string>
<key>Key</key> <string>email_preference</string>
<key>DefaultValue</key> <true/>
</dict>
<dict>
<key>Type</key> <string>PSToggleSwitchSpecifier</string>
<key>Title</key> <string>BlogSpot</string>
<key>Key</key> <string>blogspot_preference</string>
<key>DefaultValue</key> <true/>
</dict>
<!-- Automatic Email Enable -->
<dict>
<key>Type</key> <string>PSGroupSpecifier</string>
<key>Title</key> <string>Automatic Emailing</string>
</dict>
<dict>
<key>Type</key> <string>PSToggleSwitchSpecifier</string>
<key>Title</key> <string>Always Send to Email</string>
<key>Key</key> <string>autoblogspot_preference</string>
<key>DefaultValue</key> <true/>
</dict>
<!-- Calendar -->
<dict>
<key>Type</key> <string>PSRadioGroupSpecifier</string>
<key>Title</key> <string>First Day of the Week</string>
<key>Key</key> <string>firstDayOfTheWeek_preference</string>
<key>Values</key>
<array>
<integer>0</integer>
<integer>1</integer>
<integer>2</integer>
<integer>3</integer>
<integer>4</integer>
<integer>5</integer>
<integer>6</integer>
</array>
<key>Titles</key>
<array>
<string>Sunday</string>
<string>Monday</string>
<string>Tuesday</string>
<string>Wednesday</string>
<string>Thursday</string>
<string>Friday</string>
<string>Saturday</string>
</array>
</dict>
<dict>
<key>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
At the very end of the plist you have a dangling key and dict tag.
Lines #90 and #91.
</dict>
<dict>
<key>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
Should be something like:
</dict>
<dict />
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
or
</dict>
<dict>
<key>key</key><string>string</string>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
I found this out using TextMate. Bundles -> Property List -> Validate Syntax. Doesn't tell you the exact problem, but gets you to the area.
You can also get a line # to look at by trying to open the plist in the Property List Editor app (/Developer/Applications/Utilities/Property List Editor.app)
Plists are XML, so any XML validator will find major problems in your syntax. Rule of thumb, though, is for every tag you need a close tag. For every key you need a value.
Empty tags should be <tag /> not <tag></tag>.
How do you set your Cocoa application as the default web browser?
I want to create an application that is launched by default when the user clicks on an HTTP or HTTPS link in other applications (Mail, iChat etc.).
There are four steps to making an app that can act as the default web browser. The first three steps allow your app to act as a role handler for the relevant URL schemes (HTTP and HTTPS) and the final step makes it the default role handler for those schemes.
1) Add the URL schemes your app can handle to your application's info.plist file
To add support for http:// and https:// you'd need to add the following to your application's info.plist file. This tells the OS that your application is capable of handling HTTP and HTTP URLs.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>http URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>http</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>Secure http URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
</dict>
</array>
2) Write an URL handler method
This method will be called by the OS when it wants to use your application to open a URL. It doesn't matter which object you add this method to, that'll be explicitly passed to the Event Manager in the next step. The URL handler method should look something like this:
- (void)getUrl:(NSAppleEventDescriptor *)event
withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
// Get the URL
NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject]
stringValue];
//TODO: Your custom URL handling code here
}
3) Register the URL handler method
Next, tell the event manager which object and method to call when it wants to use your app to load an URL. In the code here I'm passed self as the event handler, assuming that we're calling setEventHandler from the same object that defines the getUrl:withReplyEvent: method.
You should add this code somewhere in your application's initialisation code.
NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager];
[em
setEventHandler:self
andSelector:#selector(getUrl:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
Some applications, including early versions of Adobe AIR, use the alternative WWW!/OURL AppleEvent to request that an application opens URLs, so to be compatible with those applications you should also add the following:
[em
setEventHandler:self
andSelector:#selector(getUrl:withReplyEvent:)
forEventClass:'WWW!'
andEventID:'OURL'];
4) Set your app as the default browser
Everything we've done so far as told the OS that your application is a browser, now we need to make it the default browser.
We've got to use the Launch Services API to do this. In this case we're setting our app to be the default role handler for HTTP and HTTPS links:
CFStringRef bundleID = (CFStringRef)[[NSBundle mainBundle] bundleIdentifier];
OSStatus httpResult = LSSetDefaultHandlerForURLScheme(CFSTR("http"), bundleID);
OSStatus httpsResult = LSSetDefaultHandlerForURLScheme(CFSTR("https"), bundleID);
//TODO: Check httpResult and httpsResult for errors
(It's probably best to ask the user's permission before changing their default browser.)
Custom URL schemes
It's worth noting that you can also use these same steps to handle your own custom URL schemes. If you're creating a custom URL scheme it's a good idea to base it on your app's bundle identifier to avoid clashes with other apps. So if your bundle ID is com.example.MyApp you should consider using x-com-example-myapp:// URLs.
macOS Big Sur and Up
Copy and paste this code into your info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>Web site URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>http</string>
<string>https</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>http URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>http</string>
</array>
</dict>
<dict>
<key>CFBundleURLName</key>
<string>Secure http URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>HTML document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.html</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>XHTML document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.xhtml</string>
</array>
</dict>
</array>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>GIF image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.compuserve.gif</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>HTML document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.html</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>XHTML document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.xhtml</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>JavaScript script</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.netscape.javascript-source</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>JPEG image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.jpeg</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>MHTML document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.ietf.mhtml</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>HTML5 Audio (Ogg)</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.xiph.ogg-audio</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>HTML5 Video (Ogg)</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.xiph.ogv</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>PNG image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.png</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>SVG document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.svg-image</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>Plain text document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.text</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>HTML5 Video (WebM)</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.webmproject.webm</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>WebP image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.webmproject.webp</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>org.chromium.extension</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>PDF Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.adobe.pdf</string>
</array>
</dict>
</array>
Your app will be shown in the system preferences and will be default browser
Make sure you do this
func application(_ application: NSApplication, open urls: [URL]) {
// do a for loop, I recommend it
}
If you just want to change the default helper app for http(s), you can do so in the Safari preferences. There you’ll find a drop down which will let you select all the registered handler applications for http. To automatically have the app set itself as the default browser see the previous instructions.
In order to appear as an option on System Preferences > General > Default web browser (at least for macOS 11) you need to add the document types for HTML and XHTML to the Info.plist (after the 4 steps already described on the accepted answer), like this:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>HTML document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.html</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>XHTML document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>public.xhtml</string>
</array>
</dict>
</array>