You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.2 KiB

6 years ago
  1. // Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
  2. //
  3. // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
  4. // copy, modify, and distribute this software in source code or binary form for use
  5. // in connection with the web services and APIs provided by Facebook.
  6. //
  7. // As with any software that integrates with the Facebook platform, your use of
  8. // this software is subject to the Facebook Developer Principles and Policies
  9. // [http://developers.facebook.com/policy/]. This copyright notice shall be
  10. // included in all copies or substantial portions of the software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. import FBSDKShareKit
  19. @testable import FacebookCore
  20. /**
  21. A utility class for sharing through the graph API. Using this class requires an access token that
  22. has been granted the "publish_actions" permission.
  23. GraphSharer network requests are scheduled on the current run loop in the default run loop mode
  24. (like NSURLConnection). If you want to use GraphSharer in a background thread, you must manage the run loop
  25. yourself.
  26. */
  27. public final class GraphSharer<Content: ContentProtocol> {
  28. fileprivate let sdkSharer: FBSDKShareAPI
  29. fileprivate let sdkShareDelegate: SDKSharingDelegateBridge<Content>
  30. /// The message the person has provided through the custom dialog that will accompany the share content.
  31. public var message: String? {
  32. get {
  33. return sdkSharer.message
  34. }
  35. set {
  36. sdkSharer.message = newValue
  37. }
  38. }
  39. /// The graph node to which content should be shared.
  40. public var graphNode: String? {
  41. get {
  42. return sdkSharer.graphNode
  43. }
  44. set {
  45. sdkSharer.graphNode = newValue
  46. }
  47. }
  48. /// The access token used when performing a share. The access token must have the "publish_actions" permission granted.
  49. public var accessToken: AccessToken? {
  50. get {
  51. let accessToken: FBSDKAccessToken? = sdkSharer.accessToken
  52. return accessToken.flatMap(AccessToken.init)
  53. }
  54. set {
  55. sdkSharer.accessToken = newValue.map { $0.sdkAccessTokenRepresentation }
  56. }
  57. }
  58. /**
  59. Create a new Graph API sharer.
  60. - parameter content: The content to share.
  61. */
  62. public init(content: Content) {
  63. sdkSharer = FBSDKShareAPI()
  64. sdkShareDelegate = SDKSharingDelegateBridge()
  65. sdkShareDelegate.setupAsDelegateFor(sdkSharer)
  66. sdkSharer.shareContent = ContentBridger.bridgeToObjC(content)
  67. }
  68. }
  69. //--------------------------------------
  70. // MARK: - Share
  71. //--------------------------------------
  72. extension GraphSharer {
  73. /**
  74. Attempt to share `content` with the graph API.
  75. - throws: If the content fails to share.
  76. */
  77. public func share() throws {
  78. var error: Error?
  79. let completionHandler = sdkShareDelegate.completion
  80. sdkShareDelegate.completion = {
  81. if case .failed(let resultError) = $0 {
  82. error = resultError
  83. }
  84. }
  85. sdkSharer.share()
  86. sdkShareDelegate.completion = completionHandler
  87. if let error = error {
  88. throw error
  89. }
  90. }
  91. }
  92. //--------------------------------------
  93. // MARK: - ContentSharingProtocol
  94. //--------------------------------------
  95. extension GraphSharer: ContentSharingProtocol {
  96. /// The content that is being shared.
  97. public var content: Content {
  98. get {
  99. guard let swiftContent: Content = ContentBridger.bridgeToSwift(sdkSharer.shareContent) else {
  100. fatalError("Content of our private sharer has changed type. Something horrible has happened.")
  101. }
  102. return swiftContent
  103. }
  104. }
  105. /// The completion handler to be invoked upon the share performing.
  106. public var completion: ((ContentSharerResult<Content>) -> Void)? {
  107. get {
  108. return sdkShareDelegate.completion
  109. }
  110. set {
  111. sdkShareDelegate.completion = newValue
  112. }
  113. }
  114. /// Whether or not this sharer fails on invalid data.
  115. public var failsOnInvalidData: Bool {
  116. get {
  117. return sdkSharer.shouldFailOnDataError
  118. }
  119. set {
  120. sdkSharer.shouldFailOnDataError = newValue
  121. }
  122. }
  123. /**
  124. Validates the content on the receiver.
  125. - throws: If The content could not be validated.
  126. */
  127. public func validate() throws {
  128. try sdkSharer.validate()
  129. }
  130. }
  131. //--------------------------------------
  132. // MARK: - Convenience
  133. //--------------------------------------
  134. extension GraphSharer {
  135. /**
  136. Share a given `content` to the Graph API, with a completion handler.
  137. - parameter content: The content to share.
  138. - parameter completion: The completion handler to invoke.
  139. - returns: Whether or not the operation was successfully started.
  140. - throws: If the share fails.
  141. */
  142. @discardableResult
  143. public static func share(_ content: Content, completion: ((ContentSharerResult<Content>) -> Void)? = nil) throws -> GraphSharer {
  144. let sharer = self.init(content: content)
  145. sharer.completion = completion
  146. try sharer.share()
  147. return sharer
  148. }
  149. }