PhoneGapによるiPhoneアプリ作成（Object-C拡張）

# PhoneGapによるiPhoneアプリ作成（Object-C拡張）


## はじめに
ハイブリッドアプリ作成のための覚え書きです。忘れないためのメモ程度ですので、初心者に懇切丁寧に教えるコンセプトでないため、ところどころ、はしょったりしてます。

## Object-Cによる機能拡張
PhoneGapeを使用するにあたり、やはり限界があります。そのため、ChildBrowserのObject-Cコードを拡張し、新しく機能を追加することにしました。今回はSafariが立ち上がるアイコンを押すと、代わりにアクションシートが起動し、Safariで開く、Twitter共有、メール送信、URLコピーとしてChildBrowserで閲覧中のURLを引数に渡す機能を追加します。個々の機能はFrameworkとして提供されているものを呼び出します。

## アクションシートの追加
ChildBrowserViewController.xib から ChildBrowserViewController.h へアクションシート起動用アイコンをControlキーを押しながらドラッグします。するとボタン接続情報の設定がでるので、値を、

Connection: Action
Name: safariBtn（ここはアイコンと同じ奴）
Event: Touch Up Inside
Arguments: Sender

に設定。次に@interface にUIActionSheetDelegate を追記


```objc:ChildBrowserViewController.h

@interface ChildBrowserViewController : UIViewController <UIWebViewDelegate, UIActionSheetDelegate>{}

```

すると、ChildBrowserViewController.m に- (IBAction)safariBtn:(id)sender が追記されます。
ここにアクションシートのメニューを宣言していきます。


```objc:ChildBrowserViewController.m

UIActionSheet *actionSheet = [[UIActionSheet alloc]
    initWithTitle:@"メニュー" delegate: self cancelButtonTitle:@"キャンセル" destructiveButtonTitle:@"閉じる" otherButtonTitles:@"Safariで開く",@"Twitter共有",@"メール送信",@"URLコピー", nil
];
[actionSheet showInView:self.view];
[actionSheet release];

```

次にアクションシートの内容を記述します。


```objc:ChildBrowserViewController.m

- (void)actionSheet:(UIActionSheet *) actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    
    NSString *requestPath = [[self.webView.request URL] absoluteString];
    NSURLRequest* requestURL = self.webView.request;
    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    
    switch ((buttonIndex)) {
        case 0:
            /* チャイルドブラウザを閉じる */
            if (self.delegate != nil) {
                [self.delegate onClose];
            }
            if ([self respondsToSelector:@selector(presentingViewController)]) {
                // Reference UIViewController.h Line:179 for update to iOS 5 difference - @RandyMcMillan
                [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
            } else {
                [[self parentViewController] dismissModalViewControllerAnimated:YES];
            }
            break;
            
        case 1:
            /* Safariで開く */
            if (self.delegate != nil) {
                [self.delegate onOpenInSafari];
            }
            
            if (self.isImage) {
                NSURL* pURL = [NSURL URLWithString:self.imageURL];
                [[UIApplication sharedApplication] openURL:pURL];
            } else {
                NSURLRequest* request = self.webView.request;
                [[UIApplication sharedApplication] openURL:request.URL];
            }
            
            break;
            
        case 2:
            /* Twitterで共有 */
            if ([TWTweetComposeViewController canSendTweet]) {
                // ツイート用の画面を表示する
                TWTweetComposeViewController *tweetViewController = 
                                      [[TWTweetComposeViewController alloc] init];
                [tweetViewController setInitialText: @"Tweet文"];
                
                [tweetViewController addURL: requestURL.URL];
                [self presentViewController:tweetViewController animated:YES completion:nil];
                
                [tweetViewController release];
            }else {
                // ツイッター設定なし
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Teitter未設定"
                                                      message:@"アカウントの設定が未設定です。"
                                                      delegate:nil
                                                      cancelButtonTitle:nil
                                                      otherButtonTitles:@"OK" , nil];
                [alert show];
                [alert release];
            }
            
            break;
            
        case 3:
            /* メール送信 */
            if( [ MFMailComposeViewController canSendMail ] == NO )
            {
               [ [ [ [ UIAlertView alloc ] initWithTitle:@"エラー" message:@"メールアカウントを設定してください" 
                                    delegate:nil 
                                    cancelButtonTitle:nil 
                                    otherButtonTitles:nil ] autorelease ] show ];
            }
            else
            {
                MFMailComposeViewController * controller = 
                             [ [ [ MFMailComposeViewController alloc ] init ] autorelease ];
                                
                [ controller setSubject:@"タイトル" ];
                [ controller setMessageBody: requestPath isHTML:YES ];
                controller.mailComposeDelegate = self;
                
                [ self presentModalViewController:controller animated:YES ];
            }
            return;
            
            break;
        case 4:
            /* クリップボードへコピー */
            [pasteboard setValue:requestPath forPasteboardType:@"public.text"];
            break;
        default:
            break;
    }
}

- (void)mailComposeController:( MFMailComposeViewController* )controller didFinishWithResult:( MFMailComposeResult )result error:( NSError* )error
{
	if( error != nil )
	{
		NSLog( @"エラーが発生しました。" );
	}
	else
	{
		switch( result )
		{
			case MFMailComposeResultSent: NSLog( @"メールを送信" ); break;
			case MFMailComposeResultSaved: NSLog( @"メールを保存" ); break;
			case MFMailComposeResultCancelled: NSLog( @"キャンセル" ); break;
			case MFMailComposeResultFailed: NSLog( @"失敗" ); break;
			default: NSLog( @"不明な結果" ); break;
		}
	}
	
	[ controller dismissModalViewControllerAnimated:YES ];
	
	return;
}


```

## インポートするFramework

```objc:ChildBrowserViewController.h

#import <Twitter/TWTweetComposeViewController.h>
#import <UIKit/UIPasteboard.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>

```

PROJECTのSummaryのLinkedFrameworks and Libraries からも各Frameworkを読み込むのを忘れずに。

## まとめ
PhoneGapではある程度の拡張をObject-Cで記述することで可能になります。
ネイティブに依存するため移植性は犠牲になりますが、便利といえば便利。