初學者指南:使用社交框架與 UIActivityViewController

初學者指南:使用社交框架與 UIActivityViewController
初學者指南:使用社交框架與 UIActivityViewController
In:

你早已被截止期限壓得喘不過氣,在耗費了好幾個鐘頭之後,才發現有夠困難甚至做不出來,於是又再度坐在電腦前面浪費另外好幾個鐘頭,就只為了整合 Facebook 或 Twitter 的 SDK 。不然的話,你還能夠做些什麼呢?或許可以開始設想幾十個不同的藉口來向老闆或客戶說明無法交付 App 的原因?或許你已經感到口乾舌燥非常窒息?或者其實有另外一種簡便的作法,可以毫不費力地在你的 App 中加入分享功能?

好吧,親愛的讀者們,但願沒人遭遇過我剛才所描述的窘況,針對那個問題,確實存在一個完美而快速的解決方案。事實上,這個解決方案有個名稱,叫做 Social (社交)框架,而且就內建在 iOS SDK 當中。許多人很可能早已使用過,但是我敢打賭應該還有很多開發者不知道此框架的存在,也不知道只需要幾分鐘的時間即可在 App 中實現分享功能!一點也不誇張!

如你所知, Apple 好久以前就已經在 iOS 中加入了 Facebook 和 Twitter 的發文功能。顯然這些基本功能已經具備了,但是如果要在 App 中加入更進階的功能,無疑需要藉助適當的 SDK 才有辦法達成。在本文中,我們討論的不是這種情況。我們關注的是第一種情況,更精確地說,我們關注的是如何使用 iOS 內建的發文功能。我們即將看到,只要使用 Social 框架就能夠在範例 App 中使用預設的發文視圖控制器, iOS 會幫忙處理其他所有的事情。我們不需要處理登入、認證、建立自訂視圖等議題。簡單地說,我們拿到一個「黑盒子」,再組合一些程式碼,就可以使用了。

除此之外,我們隨後還會討論到一個特殊的控制器,叫做 UIActivityViewController 。或許你不曾聽聞過,但是你肯定見過也用過:

t42_1_activityVCSimulator

運用此控制器不僅能夠讓你使用內建的分享選項,還能夠使用其他的功能,像是寄送電子郵件、簡訊、列印等。事實上,會出現哪些選項將因你要分享的內容而有所不同,不過對我們而言仍然是非常好用的工具。相信我,不是我誇大,但是真的只需要 2 行程式碼就能夠把這項功能整合到你的 App 當中,你稍後就可以自己親眼見證。

如果你渴望知道如何實現前述的任務,也非常希望能夠在下一個 App 中加以使用,那麼請繼續閱讀本文,你將發現非常簡單但是實用的技巧。我要介紹的雖然不是 iOS 8 的新功能,但是仍然非常值得被關注,因為此功能將能夠為所有開發者提供很大的彈性。那麼就讓我們開始吧。

範例 App 概觀

本文的範例 App 將會非常單純。只會有一個視圖控制器(我們將會保留 Xcode 自動建立的那個預設視圖控制器),而此視圖控制器只會有 2 個元件:一個位於上方的工具列(只有一個按鈕項目),以及位於工具列正下方的文字視圖。這將會是筆記 App 的一部分,提供文字視圖讓使用者輸入文字,隨後發文到 Facebook 和 Twitter 。介面的模樣如下圖所示:

t42_2_demo_app_sample

工具列按鈕項目將用來顯示動作表單( Action Sheet ),依序提供下列 3 個選項:

  1. Share on Facebook(分享到 Facebook )
  2. Share on Twitter(分享到 Twitter )
  3. More(更多)

針對前 2 個選項,我們將使用到 Social 框架,並且將顯示 iOS 提供的預設(內建)發文( Compose )視圖控制器來輸入文字並且發佈( Post )。至於第 3 個選項則會顯示 UIActivityViewController ,同樣可以在其中看到前 2 個分享選項。

t42_3_demo_app_sample_2

下面的截圖畫面示範的是由 iOS 所提供的用來將文字張貼至 Twitter 的發文視圖控制器:

t42_4_twitter_post

另外還有一個我必須特別提出來說明的重點,就是在執行此 App 之前,必須先在設備上登入 Facebook 和 Twitter 。在本文後續的內容中,我將展示如何達成此目的,不過現在只需要先記住這點就可以了。當然了,在我們的程式碼中,也會考慮到使用者尚未登入社群網路的情況,並且顯示適當的訊息。這些稍後都會詳加探討。

如你所知,本文的範例 App 製作起來一點也不困難,所以這次我就不提供 Starter 專案了。我們從頭開始打造,只需要 5 分種時間,就可以準備好使用 Social 框架及其提供的分享功能。不過如果你只想要閱讀文章然後直接測試範例 App 的話,一樣不成問題;在本文最後可以找到下載網址。

打造 App 及其 UI

現在就讓我們從在 Xcode 中建立新專案開始吧。在建立的時候,請確定設定細節如下:

  • 建立 Single-View Application
  • 將 App 命名為 EasyShare (或者任何你喜歡的名稱)
  • 選取 Swift 作為專案的語言
  • 將 App 的目標裝置設定為 iPhone

當 Xcode 準備好專案之後,直接來到 Interface Builder 設定唯一的場景。首先,在最上方加入工具列,就在狀態列的下方( Y = 20 )。如果想要的話,也可以設定其色調( Tint Color )。在本範例 App 的實作中,我使用的色碼是 #F39C12 。然後在工具列中入一顆列按鈕項目(右邊是不錯的位置)。在 Attributes Inspector 中將其識別碼設定為 Action ,並設定其色調為白色。

接著,從 Object Library 取得 textview 元件,並且放置到場景中。將其外框設定成如下所示:

  • X = 10
  • Y = 74
  • Width = 580
  • Height = 300

在接下來的篇幅中,我們會為此文字視圖加入框線與圓角,所以目前先這樣就可以了。別忘了移除預設的那段「 Lorem ipsum 」文字。

現在輪到設定約束的時刻了。我們剛才加入的子視圖都非常簡單,所以要設定約束也非常容易。讓我們開始動手吧,為了避免遭遇任何衝突,下列截圖畫面顯示的是我所設定的約束。關於工具列的部分:

t42_5_constraints_toolbar

以及文字視圖的部分:

t42_6_constraints_textview

場景最後應該如下圖所示:

t42_7_scene_ib

接著,我們將一個 IBOutlet 屬性連接到文字視圖,並且將一個 IBAction 函式連接到列按鈕項目。在 ViewController.swift 檔案中,在此類別的開頭處加入下列這行程式碼:

@IBOutlet weak var noteTextview: UITextView!

然後將之與文字視圖相連。此外,將下列的 IBAction 函式連接到列按鈕項目:

@IBAction func showShareOptions(sender: AnyObject) {
}

我們大部分的工作都會在上述的函式中完成,不過目前先這樣就可以了。

因為我們已經開始加入一些簡單的程式碼了,所以也讓我們把下列的自訂函式加入到 ViewController 中吧。我會讓文字視圖具備圓角外框以及框線:

func configureNoteTextView() {
    noteTextview.layer.cornerRadius = 8.0
    noteTextview.layer.borderColor = UIColor(white: 0.75, alpha: 0.5).CGColor
    noteTextview.layer.borderWidth = 1.2
}

第 1 行的用途是導圓角,後續的 2 行則是分別設定框線顏色與寬度。

viewDidLoad() 函式中,我們要呼叫的是:

override func viewDidLoad() {
    super.viewDidLoad()

    configureNoteTextView()
}

最後,將 Social 框架加入到專案中,因為我們馬上就會需要使用到。點擊 Project Navigator 中的專案項目,然後選取 General 分頁。往下捲動直到 Linked Frameworks and Libraries ,然後點擊加號( + )按鈕。在出現的強制回應視窗的搜尋列中輸入「 social 」,選取並按下 Add 以便新增:

t42_8_select_framework

Social.framework 現在應該會出現在 Linked Frameworks and Libraries 區段中,如下圖所示:

t42_9_linked_framework

現在來到最後一個步驟,開啟 ViewController.swift 檔案,來到此檔案的開頭,加入下列這行:

import Social

這樣就可以了。對於新手而言,這樣就夠了,因為我們的範例 App 已經設定完成,等著我們加入分享的功能。你現在可以先嘗試執行此 App ,看看會是什麼模樣:

t42_2_demo_app_sample

顯示分享選項

我們在範例 App 中所提供的分享選項,都可以從動作表單操作,而動作表單則會在點擊了動作列按鈕項目時出現。基於此目的,我們稍早前建立了 showShareOptions(_:) IBAction 函式。下列的截圖展示的是此行為的效果:

t42_3_demo_app_sample_2

就讓我們開始動手吧,首先要考慮的是鍵盤。就算鍵盤出現了而且文字視圖正在編輯,列按鈕項目也要能夠被點擊,所以第一步是要將鍵盤隱藏起來:

@IBAction func showShareOptions(sender: AnyObject) {
    // 如果鍵盤跑出來的話,則隱藏鍵盤
    if noteTextview.isFirstResponder() {
        noteTextview.resignFirstResponder()
    }
}

現在,我們可以初始化新的通知控制器,並且將其樣式設定為動作表單:

@IBAction func showShareOptions(sender: AnyObject) {
    ...

    let actionSheet = UIAlertController(title: "", message: "Share your Note", preferredStyle: UIAlertControllerStyle.ActionSheet)
}

如你所見,我們需要在動作表單中顯示 3 個選項,所以我們需要 3 個對應的動作。不過別忘了我們應該提供一個額外的按鈕給使用者;用來隱藏動作表單而無須選擇 3 個選項之一,因此我們總共必須建立 4 個通知動作。程式碼如下:

@IBAction func showShareOptions(sender: AnyObject) {
    ...

    // 設定分享筆記至 Twitter 的新動作
    let tweetAction = UIAlertAction(title: "Share on Twitter", style: UIAlertActionStyle.Default) { (action) -> Void in

    }


    // 設定分享至 Facebook 的新動作
    let facebookPostAction = UIAlertAction(title: "Share on Facebook", style: UIAlertActionStyle.Default) { (action) -> Void in

    }

    // 設定顯示 UIActivityViewController 的新動作
    let moreAction = UIAlertAction(title: "More", style: UIAlertActionStyle.Default) { (action) -> Void in

    }


    let dismissAction = UIAlertAction(title: "Close", style: UIAlertActionStyle.Cancel) { (action) -> Void in

    }


    actionSheet.addAction(tweetAction)
    actionSheet.addAction(facebookPostAction)
    actionSheet.addAction(moreAction)
    actionSheet.addAction(dismissAction)

    presentViewController(actionSheet, animated: true, completion: nil)
}

這樣就可以了。在這段程式碼的最後,我們會將動作表單呈現出來。現在你可以執行此 App ,並且使用工具列按鈕項目來顯示此動作表單。這些選項現在還沒有功能,不過從下一節開始,我們將會逐步補上缺漏的程式碼,讓我們能夠將筆記分享到 Twitter 和 Facebook 。

發文到 Twitter

如前所述,使用者必須先用自己的社群網路的帳號來登入。以程式設計的術語來說,對我們而言,在嘗試顯示 Social 框架所提供的預設發文視圖控制器之前的第一步,就是檢查使用者是否已經登入成功了。如果有登入的話,便能夠正常往下繼續執行,否則的話,我們只會顯示通知視圖來提示使用者。

我們將從分享至 Twitter 開始,更精確地說,我們會建立一個判斷條件來檢查使用者是否已經登入 Twitter 帳號。稍後你將會發現,我們的焦點會放在稍早前所建立的 tweetAction 通知動作。

let tweetAction = UIAlertAction(title: "Share on Twitter", style: UIAlertActionStyle.Default) { (action) -> Void in
    // 檢查能否分享至 Twitter
    if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {

    }
    else {
        self.showAlertMessage("You are not logged in to your Twitter account.")
    }
}

如同你在上述程式碼中所看到的,實際用來檢查使用者是否已登入的是 SLComposeViewController 類別的 isAvailableForServiceType(_:) 函式,傳回的結果將會是 truefalse 。唯一的參數是一個字串數值,指出是何種社交網路。 Apple 已經將適合個別社交網路的數值指派成常數了,只要輸入開頭的 SLServiceType 即可看到所有的數值:

t42_10_service_types

在上述條件的 else 段落中,可以發現我們呼叫了名為 showAlertMessage(_:) 的函式,以便在使用者沒有登入時能夠向使用者顯示自訂的訊息。此函式尚未實作,我們會在本節結束前完成。不過我必須說,其任務只是使用我們在參數中帶入的訊息來顯示通知控制器,其存在目的單純只是為了避免一再撰寫相同的程式碼。我們會在檢查使用者是否已登入 Facebook 帳號時再度使用到此函式。

緊接著,讓我們來初始化 SLComposeViewController 類別的實體。此類別將會顯示預設的視圖控制器,我們可以用來編寫想要分享的訊息,而且更重要的是,提供了我們想要的「發佈」( Post )按鈕。

let tweetAction = UIAlertAction(title: "Share on Twitter", style: UIAlertActionStyle.Default) { (action) -> Void in
    // 檢查能否分享至 Twitter
    if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
        // 初始化預設的視圖控制器以便分享貼文
        let twitterComposeVC = SLComposeViewController(forServiceType: SLServiceTypeTwitter)

    }
    else {
        self.showAlertMessage("You are not logged in to your Twitter account.")
    }
}

同樣地,我們必須在初始化 SLComposeViewController 類別時使用適當的服務類型。

上述的類別包含了一個名為 setInitialText(_:) 的函式。透過此函式,我們可以直接將文字視圖中的文字設定到發文視圖控制器。如你所見,看起來非常方便,不過必須確定我們沒有遺漏一項單純的事實:文字長度最多 140 個字元。這是 Twitter 在發佈推文時的限制。

那麼我們應該如何繼續進行呢?很簡單,首先檢查文字視圖中的文字長度。只要小於 140 個字元,即可使用前述段落所提到過的函式,並且進行後續的處理。相反地,如果文字長度大於 140 個字元,則只會「擷取」前面的 140 個字元形成子字串,並且作為要發佈的文字。

現在將剛才討論的內容翻譯成程式碼:

let tweetAction = UIAlertAction(title: "Share on Twitter", style: UIAlertActionStyle.Default) { (action) -> Void in
    // 檢查能否分享至 Twitter
    if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
        // 初始化預設的視圖控制器以便分享貼文
        let twitterComposeVC = SLComposeViewController(forServiceType: SLServiceTypeTwitter)

        // 將筆記文字設定成預設的發文訊息
        if self.noteTextview.text.characters.count <= 140 {
            twitterComposeVC.setInitialText("\(self.noteTextview.text)")
        }
        else {
            let index = self.noteTextview.text.startIndex.advancedBy(140)
            let subText = self.noteTextview.text.substringToIndex(index)
            twitterComposeVC.setInitialText("\(subText)")
        }

    }
    else {
        self.showAlertMessage("You are not logged in to your Twitter account.")
    }
}

上述程式碼只遺漏了一個命令,就是呈現發文視圖控制器:

let tweetAction = UIAlertAction(title: "Share on Twitter", style: UIAlertActionStyle.Default) { (action) -> Void in
    // 檢查能否分享至 Twitter
    if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
        ...

        // 顯示發文視圖控制器
        self.presentViewController(twitterComposeVC, animated: true, completion: nil)
    }
    else {
        self.showAlertMessage("You are not logged in to your Twitter account.")
    }
}

有了這個視圖控制器,便準備好可以發文至 Twitter 了!

好的,差不多都就緒了,只差還沒有實作 showAlertMessage(_:) 這個自訂函式:

func showAlertMessage(message: String!) {
    let alertController = UIAlertController(title: "EasyShare", message: message, preferredStyle: UIAlertControllerStyle.Alert)
    alertController.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
    presentViewController(alertController, animated: true, completion: nil)
}

最後容我再說一句,事實上,要讓 App 能夠發文到 Twitter 所需撰寫的程式碼少之又少( Facebook 也是如此)。而且因為過程非常簡單和迅速,所以在實際執行此 App 之前,也讓我們針對 Facebook 再做一次類似的事情吧。

發文到臉書

在本節中,我們會把剛才發文到 Twitter 的事情再做一次,只是這次換成了 Facebook 。事實上,我們即將要做的事情簡單多了,因為沒有文字長度的限制,所以可以略過該檢查。

這次我們將重點擺在 facebookPostAction 通知動作。下列是完整的實作,程式碼大同小異:

let facebookPostAction = UIAlertAction(title: "Share on Facebook", style: UIAlertActionStyle.Default) { (action) -> Void in
    if SLComposeViewController.isAvailableForServiceType(SLServiceTypeFacebook) {
        let facebookComposeVC = SLComposeViewController(forServiceType: SLServiceTypeFacebook)

        facebookComposeVC.setInitialText("\(self.noteTextview.text)")

        self.presentViewController(facebookComposeVC, animated: true, completion: nil)
    }
    else {
        self.showAlertMessage("You are not connected to your Facebook account.")
    }
}

我們再次利用適當的服務類型字串數值來檢查使用者是否已經連上 Facebook 帳號。並以同樣的數值來初始化 SLComposeViewController 實體。我們將文字視圖的文字設定為發文視圖控制器的初始文字,並且呈現出來。這樣就做完了。最後,如果使用者尚未登入的話,則顯示另一個訊息。

在測試之前

範例 App 可以在實機或模擬器上測試。不過可能需要特定的動作,才能夠成功發文到社交網路。在成功看到這些貼文之前,下列的截圖展示的是尚未連結社交網路時的發文情形:

t42_11_twitter_no_connection

若要連結到社交網路,可以開啟實機或模擬器的「設定」 App 。然後分別找到這些社交網路的第一層設定:

t42_13_settings_both

若要登入 Twitter 帳號,請選取 Twitter 項目,並在接下來的視圖控制器中填入你自己的 Twitter 帳號和密碼。然後透過登入按鈕來進行連結:

t42_14_twitter_filled_in

在登入之後,將會以你帳號為名新增一行:

t42_15_twitter_logged_in

如果要變更密碼,或是從裝置上將整個帳號移除的話,可以點擊此列。

t42_16_facebook_logged_in

同樣地,你也可以連結 Facebook 帳號。只要以帳號名稱和密碼登入即可。同樣也能夠利用新增的帳號列來取消與 Facebook 之間的連結。

確定你自己已經連結至這 2 種社交網路。做完這些設定之後,便可以開始測試範例 App 了。

使用 UIActivityViewController

要提供不同的分享選項並且將其他類型的動作放在一起時, UIActivityViewController 會是很好的解決方案。每次的選項會因為要套用的動作、執行此 App 的裝置,以及是否已經登入社交網路而有所不同。最常見的選項有下列這些:

  • Send an email(寄送電子郵件)
  • Send a SMS(傳送簡訊)
  • Share on Twitter and Facebook(分享至 Twitter 和 Facebook )
  • Add to Reading List(新增至閱讀清單)
  • Copy(拷貝)
  • Print(列印)
  • Send using AirDrop(透過 AirDrop 傳送)

稍後你將會看到的是關於 UIActivityViewController 的初始化與運用,真的只要 2 行程式碼。在初始化的時候,需要餵入 2 個參數,其中第 2 個參數是選用的,所以可以設定為 nil

第 1 個參數是陣列,裡面的項目是你希望動作視圖控制器提供的動作。舉例而言,在本範例中,我們的陣列只有一個項目,就是文字視圖的文字。不過如果我們使用的是圖片視圖,我們也可以在陣列中設定其圖片。根據在此所新增的項目,系統會決定哪些項目要顯示、哪些則不用。舉例而言,「新增至閱讀清單」就不需要搭配圖片。

第 2 個參數同樣也是陣列。在此陣列中,你可以明確告訴系統你希望呈現「什麼類型的動作」。假使設定成 nil 的話,那麼所有類型的動作都將會出現在動作視圖控制器當中。

此外也可以排除那些你不想顯示的動作類型,不過我們要稍後才會介紹。就目前而言,先讓我們把重點放在第 3 個名為 moreAction 的通知動作。在下列的程式碼片段中,我們初始化了 UIActivityViewController 的實體,然後加以呈現出來:

let moreAction = UIAlertAction(title: "More", style: UIAlertActionStyle.Default) { (action) -> Void in
    let activityViewController = UIActivityViewController(activityItems: [self.noteTextview.text], applicationActivities: nil)

    self.presentViewController(activityViewController, animated: true, completion: nil)
}

假使你現在執行此 App 的話,動作表單中的 More 選項終於能夠運作了。請留意,如果你是在模擬器上執行此 App 的話,看到的選項將會比實機來得少。例如就不會有傳送簡訊的選項:

t42_1_activityVCSimulator

如前所述,身為開發者,你能夠決定要將哪些選項排除在外。你需要做的,就是利用名為 excludedActivityTypes 的屬性來設定那些選項。作法是將你不想提供的動作類型以陣列方式指派給該屬性。舉例而言,我修改了前述的程式碼片段,你會看到現在多了一行;有了這行程式碼,我們便可以排除寄信選項:

let moreAction = UIAlertAction(title: "More", style: UIAlertActionStyle.Default) { (action) -> Void in
    let activityViewController = UIActivityViewController(activityItems: [self.noteTextview.text], applicationActivities: nil)

    activityViewController.excludedActivityTypes = [UIActivityTypeMail]

    self.presentViewController(activityViewController, animated: true, completion: nil)
}

再次執行此 App ,你會發現這次看不見郵件按鈕了:

t42_18_missing_email_button

結語

身為開發者,我必須承認,先前在我首次接觸 Social 框架時,對於可以這麼容易就完成本文所需的功能,著實令我吃驚。毫無疑問的是,今天我們所練習的東西都是非常基礎的程式設計任務,希望你會覺得範例 App 非常簡單明瞭。很顯然地,無論是使用 Social 框架來提供 iOS 內建的發文功能,或是透過 UIActivityViewController ,其實不太可能滿足真實 App 的需求。那是因為這 2 種作法都需要使用到系統的元件,所以並不適用於客製化的 UI 。不過如果這點不是考慮因素的話,那麼或許會覺得本文提供的解決方案還滿方便的。如果最後決定要使用的話,可以預見的是,你只需要幾分鐘的時間,就足夠把一切都完成了。無論如何,我相信你在本文所學到的知識,將會成為你的另一項工具,而且最終將會讓你的程式設計生涯變得更輕鬆愉快。

供你參考,請從這裡下載本文完整的 Xcode 專案。

譯者簡介:陳佳新 – 奇步應用共同創辦人,開發自有 App 和網站之外,也承包各式案件。譯有多本電腦書籍,包括 O'Reilly 出版的 iOS 、 Android 、 Agile 和 Google Cloud 等主題,也在報紙上寫過小說。現與妻兒居住在故鄉彰化。歡迎造訪 https://chibuapp.com ,來信請寄到 [email protected]

原文Beginner’s Guide: Using Social Framework and UIActivityViewController

作者
Gabriel Theodoropoulos
資深軟體開發員,從事相關工作超過二十年,專門在不同的平台和各種程式語言去解決軟體開發問題。自2010年中,Gabriel專注在iOS程式的開發,利用教程與世界上每個角落的人分享知識。可以在Google+或推特關注 Gabriel。
評論
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。