Skip to content

Commit

Permalink
Support for opening URLs in Chrome
Browse files Browse the repository at this point in the history
  • Loading branch information
c99koder committed May 29, 2013
1 parent 462ce0c commit b591f3e
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 1 deletion.
8 changes: 8 additions & 0 deletions IRCCloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
224D00AA173C188100500D70 /* add.png in Resources */ = {isa = PBXBuildFile; fileRef = 224D00A8173C188100500D70 /* add.png */; };
22695F5516E8FC9900E01DF8 /* CollapsedEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = 22695F5416E8FC9800E01DF8 /* CollapsedEvents.m */; };
22695F5616E8FC9900E01DF8 /* CollapsedEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = 22695F5416E8FC9800E01DF8 /* CollapsedEvents.m */; };
2274F49F1756723F0039B4CB /* OpenInChromeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2274F49E1756723F0039B4CB /* OpenInChromeController.m */; };
2274F4A01756723F0039B4CB /* OpenInChromeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2274F49E1756723F0039B4CB /* OpenInChromeController.m */; };
227FF2A116FA128B00DBE3C5 /* HighlightsCountView.m in Sources */ = {isa = PBXBuildFile; fileRef = 227FF2A016FA128B00DBE3C5 /* HighlightsCountView.m */; };
227FF2A216FA128B00DBE3C5 /* HighlightsCountView.m in Sources */ = {isa = PBXBuildFile; fileRef = 227FF2A016FA128B00DBE3C5 /* HighlightsCountView.m */; };
228A057016D3DABA0029769C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 228A056F16D3DABA0029769C /* UIKit.framework */; };
Expand Down Expand Up @@ -225,6 +227,8 @@
224D00A8173C188100500D70 /* add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = add.png; sourceTree = "<group>"; };
22695F5316E8FC9800E01DF8 /* CollapsedEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollapsedEvents.h; sourceTree = "<group>"; };
22695F5416E8FC9800E01DF8 /* CollapsedEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollapsedEvents.m; sourceTree = "<group>"; };
2274F49D1756723F0039B4CB /* OpenInChromeController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OpenInChromeController.h; path = OpenInChrome/OpenInChromeController.h; sourceTree = SOURCE_ROOT; };
2274F49E1756723F0039B4CB /* OpenInChromeController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OpenInChromeController.m; path = OpenInChrome/OpenInChromeController.m; sourceTree = SOURCE_ROOT; };
227FF29F16FA128A00DBE3C5 /* HighlightsCountView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HighlightsCountView.h; sourceTree = "<group>"; };
227FF2A016FA128B00DBE3C5 /* HighlightsCountView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HighlightsCountView.m; sourceTree = "<group>"; };
228A056C16D3DABA0029769C /* IRCCloud.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IRCCloud.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -424,6 +428,8 @@
228A057616D3DABA0029769C /* Supporting Files */ = {
isa = PBXGroup;
children = (
2274F49D1756723F0039B4CB /* OpenInChromeController.h */,
2274F49E1756723F0039B4CB /* OpenInChromeController.m */,
22B15CF617301BAE0075EBA7 /* ECSlidingViewController */,
22D430A21725AAE9003C0684 /* UIExpandingTextView.h */,
22D430A31725AAEA003C0684 /* UIExpandingTextView.m */,
Expand Down Expand Up @@ -836,6 +842,7 @@
22B15CF4172ECCFF0075EBA7 /* EditConnectionViewController.m in Sources */,
22B15CFB17301BAF0075EBA7 /* ECSlidingViewController.m in Sources */,
22B15CFD17301BAF0075EBA7 /* UIImage+ImageWithUIView.m in Sources */,
2274F49F1756723F0039B4CB /* OpenInChromeController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -885,6 +892,7 @@
22B15CF5172ECCFF0075EBA7 /* EditConnectionViewController.m in Sources */,
22B15CFC17301BAF0075EBA7 /* ECSlidingViewController.m in Sources */,
22B15CFE17301BAF0075EBA7 /* UIImage+ImageWithUIView.m in Sources */,
2274F4A01756723F0039B4CB /* OpenInChromeController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 2 additions & 0 deletions IRCCloud/Classes/EventsTableView.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import "NetworkConnection.h"
#import "HighlightsCountView.h"
#import "Ignore.h"
#import "OpenInChromeController.h"

@protocol EventsTableViewDelegate<NSObject>
-(void)rowSelected:(Event *)event;
Expand Down Expand Up @@ -49,6 +50,7 @@
NSRecursiveLock *_lock;

IBOutlet id<EventsTableViewDelegate> _delegate;
OpenInChromeController *_openInChromeController;
}
@property (readonly) UIView *bottomUnreadView;
-(void)insertEvent:(Event *)event backlog:(BOOL)backlog nextIsGrouped:(BOOL)nextIsGrouped;
Expand Down
6 changes: 5 additions & 1 deletion IRCCloud/Classes/EventsTableView.m
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ - (void)viewDidLoad {
lp.minimumPressDuration = 1.0;
lp.delegate = self;
[self.tableView addGestureRecognizer:lp];
_openInChromeController = [[OpenInChromeController alloc] init];
}

- (void)viewWillAppear:(BOOL)animated {
Expand Down Expand Up @@ -827,7 +828,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N

- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url {
//TODO: check for irc:// URLs
[[UIApplication sharedApplication] openURL:url];
if(![_openInChromeController openInChrome:url
withCallbackURL:[NSURL URLWithString:@"irccloud://"]
createNewTab:NO])
[[UIApplication sharedApplication] openURL:url];
}

/*
Expand Down
15 changes: 15 additions & 0 deletions IRCCloud/IRCCloud-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@
<string>0.9.6</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLIconFile</key>
<string>Icon</string>
<key>CFBundleURLName</key>
<string>com.irccloud.launch</string>
<key>CFBundleURLSchemes</key>
<array>
<string>irccloud</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>0.9.6</string>
<key>LSRequiresIPhoneOS</key>
Expand Down
54 changes: 54 additions & 0 deletions OpenInChrome/OpenInChromeController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#import <Foundation/Foundation.h>

// This class is used to check if Google Chrome is installed in the system and
// to open a URL in Google Chrome either with or without a callback URL.
@interface OpenInChromeController : NSObject

// Returns a shared instance of the OpenInChromeController.
+ (OpenInChromeController *)sharedInstance;

// Returns YES if Google Chrome is installed in the user's system.
- (BOOL)isChromeInstalled;

// Opens a URL in Google Chrome.
- (BOOL)openInChrome:(NSURL *)url;

// Open a URL in Google Chrome providing a |callbackURL| to return to the app.
// URLs from the same app will be opened in the same tab unless |createNewTab|
// is set to YES.
// |callbackURL| can be nil.
// The return value of this method is YES if the URL is successfully opened.
- (BOOL)openInChrome:(NSURL *)url
withCallbackURL:(NSURL *)callbackURL
createNewTab:(BOOL)createNewTab;

@end
135 changes: 135 additions & 0 deletions OpenInChrome/OpenInChromeController.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright 2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#import <UIKit/UIKit.h>

#import "OpenInChromeController.h"

static NSString * const kGoogleChromeHTTPScheme = @"googlechrome:";
static NSString * const kGoogleChromeHTTPSScheme = @"googlechromes:";
static NSString * const kGoogleChromeCallbackScheme =
@"googlechrome-x-callback:";

static NSString * encodeByAddingPercentEscapes(NSString *input) {
NSString *encodedValue =
(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(CFStringRef)input,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8));
return encodedValue;
}

@implementation OpenInChromeController

+ (OpenInChromeController *)sharedInstance {
static OpenInChromeController *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}

- (BOOL)isChromeInstalled {
NSURL *simpleURL = [NSURL URLWithString:kGoogleChromeHTTPScheme];
NSURL *callbackURL = [NSURL URLWithString:kGoogleChromeCallbackScheme];
return [[UIApplication sharedApplication] canOpenURL:simpleURL] ||
[[UIApplication sharedApplication] canOpenURL:callbackURL];
}

- (BOOL)openInChrome:(NSURL *)url {
return [self openInChrome:url withCallbackURL:nil createNewTab:NO];
}

- (BOOL)openInChrome:(NSURL *)url
withCallbackURL:(NSURL *)callbackURL
createNewTab:(BOOL)createNewTab {
NSURL *chromeSimpleURL = [NSURL URLWithString:kGoogleChromeHTTPScheme];
NSURL *chromeCallbackURL = [NSURL URLWithString:kGoogleChromeCallbackScheme];
if ([[UIApplication sharedApplication] canOpenURL:chromeCallbackURL]) {
NSString *appName =
[[NSBundle mainBundle]
objectForInfoDictionaryKey:@"CFBundleDisplayName"];

NSString *scheme = [url.scheme lowercaseString];

// Proceed only if scheme is http or https.
if ([scheme isEqualToString:@"http"] ||
[scheme isEqualToString:@"https"]) {

NSMutableString *chromeURLString = [NSMutableString string];
[chromeURLString appendFormat:
@"%@//x-callback-url/open/?x-source=%@&url=%@",
kGoogleChromeCallbackScheme,
encodeByAddingPercentEscapes(appName),
encodeByAddingPercentEscapes([url absoluteString])];
if (callbackURL) {
[chromeURLString appendFormat:@"&x-success=%@",
encodeByAddingPercentEscapes([callbackURL absoluteString])];
}
if (createNewTab) {
[chromeURLString appendString:@"&create-new-tab"];
}

NSURL *chromeURL = [NSURL URLWithString:chromeURLString];

// Open the URL with Google Chrome.
return [[UIApplication sharedApplication] openURL:chromeURL];
}
} else if ([[UIApplication sharedApplication] canOpenURL:chromeSimpleURL]) {
NSString *scheme = [url.scheme lowercaseString];

// Replace the URL Scheme with the Chrome equivalent.
NSString *chromeScheme = nil;
if ([scheme isEqualToString:@"http"]) {
chromeScheme = kGoogleChromeHTTPScheme;
} else if ([scheme isEqualToString:@"https"]) {
chromeScheme = kGoogleChromeHTTPSScheme;
}

// Proceed only if a valid Google Chrome URI Scheme is available.
if (chromeScheme) {
NSString *absoluteString = [url absoluteString];
NSRange rangeForScheme = [absoluteString rangeOfString:@":"];
NSString *urlNoScheme =
[absoluteString substringFromIndex:rangeForScheme.location + 1];
NSString *chromeURLString =
[chromeScheme stringByAppendingString:urlNoScheme];
NSURL *chromeURL = [NSURL URLWithString:chromeURLString];

// Open the URL with Google Chrome.
return [[UIApplication sharedApplication] openURL:chromeURL];
}
}
return NO;
}

@end

0 comments on commit b591f3e

Please sign in to comment.