FB Messenger 和 iMessage 的 UIActivityViewController 中透明 PNG 的问题

Issues with transparent PNG in UIActivityViewController for FB Messenger and iMessage

我一直在使用以下代码调用 UIActivityViewController 以通过各种社交媒体应用程序共享贴纸:

if let image = sticker.getUIImage(), let imgData = UIImagePNGRepresentation(image) {
    let activityVC = UIActivityViewController(activityItems: [imgData], applicationActivities: nil)
    activityVC.popoverPresentationController?.sourceView = gesture.view
    self.present(activityVC, animated: true, completion: nil)
} else {
    ErrorHandler.handleError(STICKER_IMAGE_NOT_FOUND, sticker)
}

在最近更新 FB Messenger(版本 98.0)之前,此代码一直运行良好。现在它显示错误 "Couldn't load content"。 FB Messenger 似乎更喜欢这样的 URL:

if let item = sticker.getImageURL() {
    let activityVC = UIActivityViewController(activityItems: [item], applicationActivities: nil)
    activityVC.popoverPresentationController?.sourceView = gesture.view
    self.present(activityVC, animated: true, completion: nil)
} else {
    ErrorHandler.handleError(STICKER_IMAGE_NOT_FOUND, sticker)
}

这适用于 FB Messenger,但 iMessage 显示透明的 PNG,背景为黑色。 我正在查看 UIActivityViewControllerCompletionWithItemsHandler,但讨论指出它在 activity 之后运行,对于我需要做的事情来说太晚了。我还尝试为 activityType 创建一个返回 UIActivityType.message 的自定义 UIActivity,但它被添加到控制器的底部而不是接管默认值。

有没有办法拦截 UIActivityViewController 中的项目选择,以便我可以使用 MFMessageComposeViewController 并将 UIImagePNGRepresentation 添加到消息中,并允许所有其他人使用 URL?

是否有我可以传递给 UIActivityViewController 的特定参数类型,它会在所有社交应用程序中正确显示透明 PNG?

TIA 麦克

绕回来结束这个。我最终从普遍使用 UIActivityViewController 切换到一个系统,该系统可以自定义为每种类型的服务完成的操作。我使用 Bob de Graaf 的 BDGShare。我构建了应用程序支持的服务列表,为每个服务显示一个按钮,然后切换到跳转到每种类型的共享。以防万一有人在做这件事,这是我想出的:

应用希望支持的分享类型:

public enum ShareServiceType:Int {
    case iMessage=0, facebook, twitter, instagram, whatsApp, facebookMessenger, email, more
}

A class 存储有关共享服务类型的信息

public class ShareTargetVO: NSObject
{
    var icon:String!
    var label:String!
    var type:ShareServiceType

    init( serviceType:ShareServiceType, icon:String, label:String )
    {
        self.type = serviceType
        self.icon = icon
        self.label = label
    }
}

我的社交网络助手中用于填充可用服务列表的功能:

static func getShareTargetList(for sticker : ReeSticker) -> [ShareTargetVO] {
    var services:Array<ShareTargetVO> = []

    // Check to see which capabilities are present and add buttons
    if (BDGShare.shared().isAvailable(forServiceType: SLServiceTypeFacebook)) {
        services.append(ShareTargetVO(serviceType: ShareServiceType.facebook, icon: "Icon-Share-Facebook", label: "Facebook"))
    }
    // Checking for facebook service type because there's no availability check with FBSDK for messenger (could be rolled into the lib)
    if (BDGShare.shared().isAvailable(forServiceType: SLServiceTypeFacebook) && !sticker.type.doesContain("video")) {
        services.append(ShareTargetVO(serviceType: ShareServiceType.facebookMessenger, icon: "Icon-Share-Messenger", label: "Messenger"))
    }
    if (BDGShare.shared().isAvailable(forServiceType: SLServiceTypeTwitter)) {
        services.append(ShareTargetVO(serviceType: ShareServiceType.twitter, icon: "Icon-Share-Twitter", label: "Twitter"))
    }
    if (BDGShare.shared().canSendSMS()) {
        services.append(ShareTargetVO(serviceType: ShareServiceType.iMessage, icon: "Icon-Share-Messages", label: "Messages"))
    }
    if UIApplication.shared.canOpenURL(URL(string: "whatsapp://")! as URL) && !sticker.type.contains("video") {
        services.append(ShareTargetVO(serviceType: ShareServiceType.whatsApp, icon: "Icon-Share-Whatsapp", label: "What's App?"))
    }
    if UIApplication.shared.canOpenURL(URL(string: "instagram://app")! as URL) && !sticker.type.contains("video") {
        services.append(ShareTargetVO(serviceType: ShareServiceType.instagram, icon: "Icon-Share-Instagram", label: "Instagram"))
    }
    if (BDGShare.shared().canSendEmail()) {
        services.append(ShareTargetVO(serviceType: ShareServiceType.email, icon: "Icon-Share-Mail", label: "Email"))
    }
    services.append(ShareTargetVO(serviceType: ShareServiceType.more, icon: "Icon-Share-More", label: "More"))

    return services
}

我的视图控制器中的一个函数,用于填充按钮的 UICollectionView,以共享仅限于从列表函数返回的那些服务:

func layoutShareButtons() {

    let f = self.view.frame
    let btnWidth = f.width * 0.82
    let bannerWidth = btnWidth + 10

    mask = UIView(frame: CGRect(x: 0, y: 0, width: f.width, height: f.height))
    mask.backgroundColor = .black
    mask.alpha = 0.3
    self.view.addSubview(mask)

    buttonList = SocialHelper.getShareTargetList(for: self.sticker)

    let buttonGridLayout = UICollectionViewFlowLayout()
    buttonGridLayout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
    buttonGridLayout.itemSize = CGSize(width: 60, height: 60)
    buttonGridLayout.scrollDirection = .horizontal

    buttonListView = UICollectionView(frame: CGRect(x: (f.width - bannerWidth) / 2,
                                                    y: self.preview.frame.origin.y + self.preview.frame.height + 10,
                                                    width: bannerWidth,
                                                    height: 80),
                                      collectionViewLayout: buttonGridLayout)
    buttonListView.register(ShareButtonCell.self, forCellWithReuseIdentifier: "shareButtonCell")
    buttonListView.dataSource = self
    buttonListView.delegate = self
    self.view.addSubview(buttonListView)

    // cancel button for sharing view
    // Button (added last to ensure it's on top of the z-order)
    cancelButton = SimpleButton(frame: CGRect(x: (f.width - bannerWidth) / 2, y: self.buttonListView.frame.origin.y + self.buttonListView.frame.height + 10, width: bannerWidth, height: 52))
    cancelButton.backgroundColor = UIColor(netHex:0x202020)
    cancelButton.layoutComponent(0, label: "Cancel")
    cancelButton.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.cancelButtonPressed(_:))))
    self.view.addSubview(self.cancelButton)
}

UICollectionView didSelect 处理程序(为了获得更好的 SoC,具体取决于您的应用程序,将 "share" 函数移除到单独的 class 中,仅用于共享实现,在此应用程序中,我们正在使用的屏幕专门分享):

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    self.share(shareTarget: buttonList[indexPath.row])
}

最后,函数调用了正确的共享类型:

func share(shareTarget: ShareTargetVO) {

    // Params to submit to service
    self.shareUrl = self.sticker.getStickerURL()

    let textStr = "" // BDGShare supports a message passed in as well but we just send the sticker

    // we need the NSData either way (sticker / video)
    var ok = true
    // try? is fine here because result is tested below
    let urlData : Data? = try? Data(contentsOf: self.shareUrl as URL)
    ok = (urlData != nil)
    var img: UIImage? = nil
    // if it's an image type then get it
    if ok {
        if (self.shareUrl.pathExtension.contains("png")) || (self.shareUrl.pathExtension.contains("jpg")) {
            img = UIImage(data: urlData! as Data)
            ok = (img != nil)
        }
    }

    if !ok {
        let alertCtrl = UIAlertController(title: "Error sending", message: "There was an error gathering the information for sending this sticker.", preferredStyle: .alert)
        alertCtrl.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
        self.present(alertCtrl, animated: true, completion: nil)
        return
    }

    switch shareTarget.type
    {
    case .iMessage:
        BDGShare.shared().shareSMS(textStr, recipient: nil, image: img, data:urlData! as Data, imageName: "sendSticker.png", completion:  {(SharingResult) -> Void in
            // Handle share result...
            self.handleShareResult(shareTarget.type, shareResult: SharingResult)
        })
        break

    case .facebook:
        BDGShare.shared().shareFacebook("", urlStr: "", image: img, completion: {(SharingResult) -> Void in
            // Handle share result...
            self.handleShareResult(shareTarget.type, shareResult: SharingResult)
        })
        break

    case .twitter: 
    ... more code for handling each type of share
    }
}

所以我曾经使用 BDGShare 来实现绕过 UIActivityViewController 的所有部分。顺便说一句 - 列表末尾的 "More" 选项调用 UIActivityViewController,因此如果用户选择,它仍然可供用户使用。

HTH,迈克