概要
SNS等のシェア機能の実装方法の説明です。
実装内容はシェアボタン押下時にアクションシートを表示し、シェアしたい内容を選びシェアするような実装内容です。
Webページを表示しシェアしていますが、それ以外でも同じような実装方法でシェア可能です。
シェア先は次の6個!(mixiは登記簿謄本が必要な為今回は対象外としました)
実装結果イメージ(「safari」と「URLをコピー」はおまけ)
この記事では、「UIApplication sharedApplication」で実装しています。
iOS6移行はUIActivityViewControllerで実装するのが楽だと思うので、iOS6移行は他の記事を参考にする方がお勧めです!
前提条件
TWITTER、FACEBOOK(iOS6以上)
Xcodeのライブラリーに「Social.framework」を追加する必要があります。
(TARGETS->MyApp->Build Phases->Link Binary With Libraries)
Google+、EverNote
Google+とEverNoteは、SDKやサービスの登録が必要となります。
(EverNoteはサービス登録が必要になるので、少し時間と手間がかかります)
簡単な概要は次の通りです。
Google+
名称 | Google+ Platform |
---|---|
URL | https://developers.google.com/+/ |
必要なライブラリ | Security.framework,SystemConfiguration.framework |
手順 | 1. APIs Console プロジェクトを作成する2. SDK をダウンロードして、サンプル アプリを実行する3. SDK のダウンロードとインストール4. プログラム修正 |
参考URL | スタートガイド(iOS)Googleでログインインタラクティブな投稿の作成 |
備考 | 開発用と製品用でIDが異なる。使えないhtmlタグがある。 |
EverNote
名称 | EverNote Developers |
---|---|
URL | https://dev.evernote.com/intl/jp/ |
必要なライブラリ | Security.framework |
手順 | 1.サンドボックスのアカウント登録(アプリごとで共通のアカウントを利用する)2. Evernote API キー取得(アプリごと別々に取得)3. SDK のダウンロードとインストール4.プログラム修正・サンドボックス上のEverNoteでテスト5.サンドボックスからプロダクションに変更依頼(アクティベーション)6.プログラム修正(プロダクションに変更(ホストを「BootstrapServerBaseURLStringSandbox」→「BootstrapServerBaseURLStringUS」)) |
参考URL | スタートガイドサンドボックスアクティベーション(プロダクションAPIキーの有効化)よくある質問 |
備考 | 開発用と製品用でIDが異なる。使えないhtmlタグがある。アクティベーションの申請時にはgoogleアカウントは使用できないので個人名・個人用メールアドレスで依頼アクティベーションの承認待ち時間は約2〜3日 |
プログラム
流れ
- アクションシートの生成
- アクションシートの表示(シェアボタン押下時)
- アクションシートの選択した内容でシェア
サンプルコード
#import <Social/Social.h> #import "EvernoteSession.h" #import "EvernoteUserStore.h" #import "EvernoteNoteStore.h" #import "GTLPlusConstants.h" #import "GPPShare.h" @implementation MainController UIActionSheet *_actionsheet; UIWebView *_webView; - (void)viewDidLoad { [super viewDidLoad]; // 1. アクションシートの生成 _actionsheet = [[UIActionSheet alloc] initWithTitle:@"共有" delegate:self cancelButtonTitle:@"キャンセル" destructiveButtonTitle:nil otherButtonTitles:@"LINE", @"Twitter", @"Facebook", @"Google+", @"メール", @"Safari", @"Evernote", @"URLをコピー", nil]; [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.co.jp"]]]; } #pragma mark - IBAction // 2. アクションシートの表示(シェアボタン押下時) - (IBAction)shareAction:(id)sender { if([[UIDevice currentDevice].model isEqualToString:@"iPad"]){ [_actionsheet showFromBarButtonItem:sender animated:YES]; } else { [_actionsheet showInView:self.view]; } } #pragma mark UIActionSheetDelegate // 3. アクションシートの選択した内容でシェア -(void)actionSheet:(UIActionSheet*)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { NSURL *url = [NSURL URLWithString:[_webView stringByEvaluatingJavaScriptFromString:@"document.URL"]]; NSString *title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"]; if (0 == buttonIndex) { // LINE NSString *contentURL = [self _escapeURL:[url absoluteString]]; NSString *contentTitleText = [self _escapeURL:title]; NSURL *lineURL = [NSURL URLWithString:[NSString stringWithFormat: @"http://line.naver.jp/R/msg/text/%@?%@", contentURL, contentTitleText]]; [[UIApplication sharedApplication] openURL:lineURL]; } else if (1 == buttonIndex) { // TWITTER SLComposeViewController *postVC = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]; [postVC setInitialText:title]; [postVC addURL:url]; [self presentViewController:postVC animated:YES completion:nil]; } else if (2 == buttonIndex) { // FACEBOOK SLComposeViewController *postVC = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook]; [postVC setInitialText:title]; [postVC addURL:url]; [self presentViewController:postVC animated:YES completion:nil]; } else if (3 == buttonIndex) { // Google+ id<GPPShareBuilder> shareBuilder = [[GPPShare sharedInstance] shareDialog]; [shareBuilder setPrefillText:title]; [shareBuilder setURLToShare:url]; [shareBuilder open]; } else if (4 == buttonIndex) { // メール NSString *conSbjText = [self _escapeURL:title]; NSString *conBodyText = [self _escapeURL:[url absoluteString]]; NSString *mail = [NSString stringWithFormat:@"mailto:%@?Subject=%@&body=%@", @"", conSbjText, conBodyText]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:mail]]; } else if (5 == buttonIndex) { // Safari [[UIApplication sharedApplication] openURL:url]; } else if (6 == buttonIndex) { // EverNote EvernoteSession *session = [EvernoteSession sharedSession]; [session authenticateWithViewController:self completionHandler:^(NSError *error) { if (!error && session.isAuthenticated){ // We're authenticated! EvernoteUserStore *userStore = [EvernoteUserStore userStore]; [userStore getUserWithSuccess:^(EDAMUser *user) { // success NSLog(@"Authenticated as %@", [user username]); EDAMNote *note = [[EDAMNote alloc] init]; note.title = title; NSString *conDes = [_webView stringByEvaluatingJavaScriptFromString: @"function a(){l=document.getElementsByTagName('meta');for(i=0;i<=l.length;i++){if(l[i].name=='description') return l[i].content}};a();"]; NSString *conImg = [_webView stringByEvaluatingJavaScriptFromString: @"function a(){l=document.getElementsByTagName('meta');for(i=0;i<=l.length;i++){if(l[i].getAttribute('property')=='og:image') return l[i].content}};a();"]; NSString *enNote = [NSString stringWithFormat:@"<p>%@</p><a href='%@'></a>%@<img src='%@' />", conDes, [self _escapeXML:[url absoluteString]], [self _escapeXML:[url absoluteString]], conImg]; note.content = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\"><en-note>%@</en-note>", enNote]; EvernoteNoteStore *store = [[EvernoteNoteStore alloc] initWithSession:[EvernoteSession sharedSession]]; [store createNote:note success:^(EDAMNote *note) { [[[UIAlertView alloc] initWithTitle:@"Evernoteに保存しました。" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; } failure:^(NSError *error) { [[[UIAlertView alloc] initWithTitle:@"Evernoteの保存に失敗しました。" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; }]; } failure:^(NSError *error) { [[[UIAlertView alloc] initWithTitle:@"Evernoteの保存に失敗しました。" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; } ]; } }]; } else if (7 == buttonIndex) { // コピー [[UIPasteboard generalPasteboard] setValue:[url absoluteString] forPasteboardType:@"public.text"]; [[[UIAlertView alloc] initWithTitle:@"URLをコピーしました。" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; } } #pragma mark - private methods - (NSString *)_escapeURL:(NSString *) url { return (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)url, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8 ); } - (NSString *)_escapeXML:(NSString *) xml { xml = [xml stringByReplacingOccurrencesOfString:@"&" withString:@"&"]; xml = [xml stringByReplacingOccurrencesOfString:@"\""withString:@"""]; xml = [xml stringByReplacingOccurrencesOfString:@"'"withString:@"'"]; xml = [xml stringByReplacingOccurrencesOfString:@">" withString:@">"]; xml = [xml stringByReplacingOccurrencesOfString:@"<" withString:@"<"]; return xml; }
エンコードについて
Line、メール、EverNoteは、直接URLをシェア出来ません。
シェアするためには、htmlのエスケープが必要になります。
urlのエスケープ(line,mail)→16進表記(文字参照)
xmlのエスケープ(EverNote)→実態参照
文字 | 実体参照 | 10進表記(文字参照) | 16進表記(文字参照) |
---|---|---|---|
"&" | & | & | & |
""" | " | " | " |
"<" | < | < | < |
">" | > | > | > |
" " | |   |   |