calvinckho / capacitor-share-extension

19 stars 5 forks source link

Error: "ShareExtension" plugin is not implemented #12

Closed chanmathew closed 1 week ago

chanmathew commented 2 weeks ago

Hi @calvinckho,

Thanks for creating this plugin.

I'm running Capacitor 6.0 and the latest 3.0.0-beta-0 of this plugin, and when I try to check for Capacitor.isPluginAvailable('ShareExtension') in the root of my Sveltekit app in my onMount function, it is returning unavailable.

And the ShareExtension functions will say Error: "ShareExtension" plugin is not implemented on iOS (i haven't tested Android yet).

Is this compatible with Capacitor 6.0?

Here's my root layout in Sveltekit, which is basically the root of the app:

onMount(async () => {
        console.log('App mounted')
        console.log(
            'ShareExtension plugin: ',
            Capacitor.isPluginAvailable('ShareExtension') ? 'available' : 'not available'
        )
        // run this as part of the app launch
        if (Capacitor.isPluginAvailable('ShareExtension')) {
            window.addEventListener('sendIntentReceived', async () => {
                await checkIntent()
            })
            await checkIntent()
        }

        // in Android, call finish when done processing the Intent
        await ShareExtension.finish()
    })

Here's my AppDelegate:

import UIKit
import Capacitor
import CapacitorShareExtension

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
     /* 
        Capacitor Share Extension
    */
    let store = ShareStore.store
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {

        var success = true
        if CAPBridge.handleOpenUrl(url, options) {
            success = ApplicationDelegateProxy.shared.application(app, open: url, options: options)
        }

        guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
              let params = components.queryItems else {
                  return false
              }
        let titles = params.filter { $0.name == "title" }
        let descriptions = params.filter { $0.name == "description" }
        let types = params.filter { $0.name == "type" }
        let urls = params.filter { $0.name == "url" }
        let webPaths = params.filter { $0.name == "webPath" }

        store.shareItems.removeAll()

        if (titles.count > 0){
            for index in 0...titles.count-1 {
                var shareItem: JSObject = JSObject()
                shareItem["title"] = titles[index].value!
                shareItem["description"] = descriptions[index].value!
                shareItem["type"] = types[index].value!
                shareItem["url"] = urls[index].value!
                shareItem["webPath"] = webPaths[index].value!
                store.shareItems.append(shareItem)
            }
        }

        store.processed = false
        let nc = NotificationCenter.default
        nc.post(name: Notification.Name("triggerSendIntent"), object: nil )

        return success
    }

    // func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    //     // Override point for customization after application launch.
    //     return true
    // }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
}

And I also copied your code in the readme for the ShareViewController.swft.

I installed your plugin, ran npx cap sync, then rebuilt my app. I've also setup a Share Extension target, with min deploy of iOS 13. The share sheet pops up when i try to share from other apps, but it just doesn't seem to load the plugin on the app side, so I can't see if the data is coming in or not.

Any help would be much appreciated!

calvinckho commented 2 weeks ago

@chanmathew I just upgraded the plugin for Capacitor 6. Please install 4.0.0-beta.0 and let me know if it works in your project.

chanmathew commented 2 weeks ago

Hi @calvinckho - Thanks for the quick update!

~~I just reinstalled the 4x beta, ran npx cap sync, rebuilt the app, and unfortunately still getting the same error. Are there other files that you think I can share that might be a good starting point to help debug?~~

It seems to be working! I realized I was also missing the packageClassList in my root capacitor.config.json, for some reason when running cap sync it only added the packageClassList it to the target nested in ios/App/capacitor.config.json. Not sure if that's on my end, maybe I need to clean my setup.

Just quick question, I noticed once I shared once to my app, the initial Share popup doesn't seem to open anymore, and it redirects straight to my app once I tap my app icon. How do I get it to trigger a UI everytime?

chanmathew commented 1 week ago

Nvm, figured it out. Thanks for your help!

For others that might come across this: I reverted the ShareViewController to inherit from SLComposeServiceViewController for now to use the default sharing prompt: class ShareViewController: SLComposeServiceViewController

and then added a didSelectPost function that basically tells the app that only share the data once the user presses "Post" in the default prompt, and then close the dialog.

    override func didSelectPost() {
        // Send data to the host app when the user taps the post button
        self.sendData()
        // Call this method to close the extension and return to the host app.
        self.close()
    }

And then I removed the self.sendData() from viewDidLoad() so it doesn't redirect the user to the app right away, but rather when they hit the post button.