Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Contact(vCard) and Calendar Events sharing, differentiate between file and plain text shares #298

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,14 @@ class ReceiveSharingIntentPlugin : FlutterPlugin, ActivityAware, MethodCallHandl
// content can only be uri or string
private fun toJsonObject(uri: Uri?, text: String?, mimeType: String?): JSONObject? {
val path = uri?.let { FileDirectory.getAbsolutePath(applicationContext, it) }
val isFile = !path.isNullOrEmpty() && text.isNullOrEmpty()
val mType = mimeType ?: path?.let { URLConnection.guessContentTypeFromName(path) }
val type = MediaType.fromMimeType(mType)
val (thumbnail, duration) = path?.let { getThumbnailAndDuration(path, type) }
?: Pair(null, null)
return JSONObject()
.put("path", path ?: text)
.put("isFile", isFile)
.put("type", type.value)
.put("mimeType", mType)
.put("thumbnail", thumbnail)
Expand Down Expand Up @@ -174,6 +176,10 @@ class ReceiveSharingIntentPlugin : FlutterPlugin, ActivityAware, MethodCallHandl
companion object {
fun fromMimeType(mimeType: String?): MediaType {
return when {
mimeType?.equals("text/x-vcard", true) == true -> FILE
mimeType?.equals("text/calendar", true) == true -> FILE
mimeType?.equals("text/x-vcalendar", true) == true -> FILE
mimeType?.equals("public.ics", true) == true -> FILE
mimeType?.startsWith("image") == true -> IMAGE
mimeType?.startsWith("video") == true -> VIDEO
mimeType?.startsWith("text") == true -> TEXT
Expand Down
34 changes: 17 additions & 17 deletions example/ios/Share Extension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>PHSupportedMediaTypes</key>
<array>
<string>Video</string>
<string>Image</string>
</array>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>100</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>100</integer>
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
<integer>1</integer>
</dict>
<string>
SUBQUERY(extensionItems, $extensionItem,
SUBQUERY($extensionItem.attachments, $attachment,
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.file-url"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.movie"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.text"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.audio"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.data"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.vcard"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "text.calendar"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "text/x-vcalendar"
OR ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.ics"
).@count == $extensionItem.attachments.@count
).@count > 0
</string>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
Expand Down
41 changes: 39 additions & 2 deletions ios/Classes/RSIShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ open class RSIShareViewController: SLComposeServiceViewController {
return
}
switch type {
case .contact:
if let contactData = data as? Data {
this.handleMedia(forVCard: contactData,
type: type,
index: index,
content: content)
}
case .text:
if let text = data as? String {
this.handleMedia(forLiteral: text,
Expand Down Expand Up @@ -144,6 +151,23 @@ open class RSIShareViewController: SLComposeServiceViewController {
}
}
}

private func handleMedia(forVCard vCardData: Data, type: SharedMediaType, index: Int, content: NSExtensionItem){
let tempPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupId)!.appendingPathComponent("TempContact.vcf")
if self.writeTempFileVCard(vCardData, to: tempPath) {
let newPathDecoded = tempPath.absoluteString.removingPercentEncoding!
sharedMedia.append(SharedMediaFile(
path: newPathDecoded,
mimeType: type == .contact ? "text/vcard": nil,
type: type
))
}
if index == (content.attachments?.count ?? 0) - 1 {
if shouldAutoRedirect() {
saveAndRedirect()
}
}
}

private func handleMedia(forFile url: URL, type: SharedMediaType, index: Int, content: NSExtensionItem) {
let fileName = getFileName(from: url, type: type)
Expand Down Expand Up @@ -179,8 +203,8 @@ open class RSIShareViewController: SLComposeServiceViewController {
}
}
}


// Save shared media and redirect to host app
private func saveAndRedirect(message: String? = nil) {
let userDefaults = UserDefaults(suiteName: appGroupId)
Expand Down Expand Up @@ -250,6 +274,19 @@ open class RSIShareViewController: SLComposeServiceViewController {
}
}

private func writeTempFileVCard(_ vCardData: Data, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) {
try FileManager.default.removeItem(at: dstURL)
}
try vCardData.write(to: dstURL);
return true;
} catch (let error){
print("Cannot write to temp file: \(error)");
return false;
}
}

private func copyFile(at srcURL: URL, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) {
Expand Down
28 changes: 26 additions & 2 deletions ios/Classes/SwiftReceiveSharingIntentPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ public class SwiftReceiveSharingIntentPlugin: NSObject, FlutterPlugin, FlutterSt
thumbnail: getAbsolutePath(for: $0.thumbnail),
duration: $0.duration,
message: message,
type: $0.type
type: $0.type,
isFile: $0.isFile
)
}
latestMedia = sharedMediaFiles
Expand Down Expand Up @@ -210,6 +211,7 @@ public class SharedMediaFile: Codable {
var duration: Double? // video duration in milliseconds
var message: String? // post message
var type: SharedMediaType
var isFile: Bool?


public init(
Expand All @@ -218,17 +220,23 @@ public class SharedMediaFile: Codable {
thumbnail: String? = nil,
duration: Double? = nil,
message: String?=nil,
type: SharedMediaType) {
type: SharedMediaType,
isFile: Bool?=nil) {
self.path = path
self.mimeType = mimeType
self.thumbnail = thumbnail
self.duration = duration
self.message = message
self.type = type
self.isFile = isFile
}
}

public enum SharedMediaType: String, Codable, CaseIterable {
case calendar
case calendarText
case vcalendar
case contact
case image
case video
case text
Expand All @@ -239,6 +247,14 @@ public enum SharedMediaType: String, Codable, CaseIterable {
public var toUTTypeIdentifier: String {
if #available(iOS 14.0, *) {
switch self {
case .calendar:
return UTType.calendarEvent.identifier
case .calendarText:
return "text.calendar"
case .vcalendar:
return "text/x-vcalendar"
case .contact:
return UTType.vCard.identifier
case .image:
return UTType.image.identifier
case .video:
Expand All @@ -254,6 +270,14 @@ public enum SharedMediaType: String, Codable, CaseIterable {
}
}
switch self {
case .calendar:
return "public.ics"
case .calendarText:
return "text.calendar"
case .vcalendar:
return "text/x-vcalendar"
case .contact:
return "public.vcard"
case .image:
return "public.image"
case .video:
Expand Down
9 changes: 9 additions & 0 deletions lib/src/data/shared_media_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class SharedMediaFile {
/// NOTE. All files are copied to a temp cache folder
final String path;

final bool? isFile;

/// Video thumbnail
final String? thumbnail;

Expand All @@ -23,6 +25,7 @@ class SharedMediaFile {

SharedMediaFile({
required this.path,
this.isFile,
required this.type,
this.thumbnail,
this.duration,
Expand All @@ -32,6 +35,7 @@ class SharedMediaFile {

SharedMediaFile.fromMap(Map<String, dynamic> json)
: path = json['path'],
isFile = json['isFile'],
thumbnail = json['thumbnail'],
duration = json['duration'],
type = SharedMediaType.fromValue(json['type']),
Expand All @@ -41,6 +45,7 @@ class SharedMediaFile {
Map<String, dynamic> toMap() {
return {
'path': path,
'isFile': isFile,
'thumbnail': thumbnail,
'duration': duration,
'type': type.value,
Expand All @@ -51,6 +56,10 @@ class SharedMediaFile {
}

enum SharedMediaType {
calendar('calendar'),
calendarText('calendarText'),
vcalendar('vcalendar'),
contact('contact'),
image('image'),
video('video'),
text('text'),
Expand Down