1- //
2- // ActionViewController.swift
3- // Action Extension
4- //
5- // Created by Jiaqi Feng on 5/22/22.
6- //
7-
81import UIKit
92import MobileCoreServices
103import UniformTypeIdentifiers
114
5+ public class SharedMediaFile : Codable {
6+ var path : String
7+ var mimeType : String ?
8+ var thumbnail : String ? // video thumbnail
9+ var duration : Double ? // video duration in milliseconds
10+ var message : String ? // post message
11+ var type : SharedMediaType
12+
13+ public init (
14+ path: String ,
15+ mimeType: String ? = nil ,
16+ thumbnail: String ? = nil ,
17+ duration: Double ? = nil ,
18+ message: String ? = nil ,
19+ type: SharedMediaType ) {
20+ self . path = path
21+ self . mimeType = mimeType
22+ self . thumbnail = thumbnail
23+ self . duration = duration
24+ self . message = message
25+ self . type = type
26+ }
27+ }
28+
29+ public enum SharedMediaType : String , Codable , CaseIterable {
30+ case image
31+ case video
32+ case text
33+ case file
34+ case url
35+
36+ public var toUTTypeIdentifier : String {
37+ if #available( iOS 14 . 0 , * ) {
38+ switch self {
39+ case . image:
40+ return UTType . image. identifier
41+ case . video:
42+ return UTType . movie. identifier
43+ case . text:
44+ return UTType . text. identifier
45+ case . file:
46+ return UTType . fileURL. identifier
47+ case . url:
48+ return UTType . url. identifier
49+ }
50+ }
51+ switch self {
52+ case . image:
53+ return " public.image "
54+ case . video:
55+ return " public.movie "
56+ case . text:
57+ return " public.text "
58+ case . file:
59+ return " public.file-url "
60+ case . url:
61+ return " public.url "
62+ }
63+ }
64+ }
65+
66+ let kSchemePrefix = " ShareMedia "
67+ let kUserDefaultsKey = " ShareKey "
68+ let kUserDefaultsMessageKey = " ShareMessageKey "
69+ let kAppGroupIdKey = " AppGroupId "
70+
1271class ActionViewController : UIViewController {
13- let hostAppBundleIdentifier = " com.jiaqi.hacki "
14- let sharedKey = " ShareKey "
72+ var hostAppBundleIdentifier = " com.jiaqi.hacki "
73+ var appGroupId = " group.com.jiaqi.hacki "
1574 var sharedText : [ String ] = [ ]
75+ var sharedMedia : [ SharedMediaFile ] = [ ]
1676 let urlContentType = UTType . url
1777 @IBOutlet weak var imageView : UIImageView !
1878
@@ -39,13 +99,11 @@ class ActionViewController: UIViewController {
3999
40100 // If this is the last item, save imagesData in userDefaults and redirect to host app
41101 if index == ( content. attachments? . count) ! - 1 {
42- let userDefaults = UserDefaults ( suiteName: " group. \( this. hostAppBundleIdentifier) " )
43- userDefaults? . set ( this. sharedText, forKey: this. sharedKey)
44- userDefaults? . synchronize ( )
102+ this. sharedMedia. removeAll ( )
103+ this. sharedMedia. append ( . init( path: item. absoluteString, type: . url) )
45104 print ( this. sharedText)
46- this. redirectToHostApp ( )
105+ this. saveAndRedirect ( )
47106 }
48-
49107 } else {
50108 self ? . dismissWithError ( )
51109 }
@@ -65,25 +123,69 @@ class ActionViewController: UIViewController {
65123 extensionContext!. completeRequest ( returningItems: [ ] , completionHandler: nil )
66124 }
67125
126+ // Save shared media and redirect to host app
127+ private func saveAndRedirect( message: String ? = nil ) {
128+ let userDefaults = UserDefaults ( suiteName: appGroupId)
129+ userDefaults? . set ( toData ( data: sharedMedia) , forKey: kUserDefaultsKey)
130+ userDefaults? . set ( message, forKey: kUserDefaultsMessageKey)
131+ userDefaults? . synchronize ( )
132+ redirectToHostApp ( )
133+ }
134+
135+ private func toData( data: [ SharedMediaFile ] ) -> Data {
136+ let encodedData = try ? JSONEncoder ( ) . encode ( data)
137+ return encodedData!
138+ }
139+
68140 private func redirectToHostApp( ) {
69- let url = URL ( string: " ShareMedia- \( hostAppBundleIdentifier) ://dataUrl= \( sharedKey) #text " )
141+ // ids may not loaded yet so we need loadIds here too
142+ loadIds ( )
143+ let url = URL ( string: " \( kSchemePrefix) - \( hostAppBundleIdentifier) :share " )
70144 var responder = self as UIResponder ?
71- let selectorOpenURL = sel_registerName ( " openURL: " )
72145
73- while ( responder != nil ) {
74- if let application = responder as? UIApplication {
75- application. performSelector ( inBackground: selectorOpenURL, with: url)
146+ if #available( iOS 18 . 0 , * ) {
147+ while responder != nil {
148+ if let application = responder as? UIApplication {
149+ application. open ( url!, options: [ : ] , completionHandler: nil )
150+ }
151+ responder = responder? . next
76152 }
153+ } else {
154+ let selectorOpenURL = sel_registerName ( " openURL: " )
77155
78- responder = responder!. next
156+ while ( responder != nil ) {
157+ if ( responder? . responds ( to: selectorOpenURL) ) ! {
158+ _ = responder? . perform ( selectorOpenURL, with: url)
159+ }
160+ responder = responder!. next
161+ }
79162 }
163+
80164 extensionContext!. completeRequest ( returningItems: [ ] , completionHandler: nil )
81165 }
82166
167+ private func loadIds( ) {
168+ // loading Share extension App Id
169+ let shareExtensionAppBundleIdentifier = Bundle . main. bundleIdentifier!
170+
171+
172+ // extract host app bundle id from ShareExtension id
173+ // by default it's <hostAppBundleIdentifier>.<ShareExtension>
174+ // for example: "com.kasem.sharing.Share-Extension" -> com.kasem.sharing
175+ let lastIndexOfPoint = shareExtensionAppBundleIdentifier. lastIndex ( of: " . " )
176+ hostAppBundleIdentifier = String ( shareExtensionAppBundleIdentifier [ ..< lastIndexOfPoint!] )
177+ let defaultAppGroupId = " group. \( hostAppBundleIdentifier) "
178+
179+
180+ // loading custom AppGroupId from Build Settings or use group.<hostAppBundleIdentifier>
181+ let customAppGroupId = Bundle . main. object ( forInfoDictionaryKey: kAppGroupIdKey) as? String
182+
183+ appGroupId = customAppGroupId ?? defaultAppGroupId
184+ }
185+
83186 @IBAction func done( ) {
84187 // Return any edited content to the host app.
85188 // This template doesn't do anything, so we just echo the passed in items.
86189 self . extensionContext!. completeRequest ( returningItems: self . extensionContext!. inputItems, completionHandler: nil )
87190 }
88-
89191}
0 commit comments