Hi everyone,
I'm developing a Capacitor plugin to display an RTSP video stream using MobileVLCKit on iOS. The Android side works perfectly, but I can’t get the iOS plugin to work — it seems my Swift file is not being detected or recognized, even though I’ve followed the official steps.
What works:
I followed the Capacitor Plugin Development Guide.
I implemented the Android version of the plugin in Java inside the android/ folder. Everything works perfectly from Angular: the plugin is recognized and calls execute correctly.
The issue on iOS:
I implemented the iOS part in Swift, using the official MobileVLCKit documentation.
I initially placed my RtspVlcPlugin.swift file in the plugin’s iOS folder, as the docs suggest.
Then I moved it directly into the main app’s ios/App/App/ folder next to AppDelegate.swift and tried manual registration.
The problem:
Even though I manually register the plugin with:
if let bridge = self.window?.rootViewController as? CAPBridgeViewController {
bridge.bridge?.registerPluginInstance(RtspVlcPlugin())
print("✅ Plugin RtspVlcPlugin registered manually.")
}
It prints the registration message just fine.
BUT from Angular, the plugin is not recognized: Capacitor.Plugins.RtspVlcPlugin has no methods, and I get this error:
"code":"UNIMPLEMENTED"
I also tried declaring @objc(RtspVlcPlugin) and extending CAPPlugin.
I’ve verified RtspVlcPlugin.swift is added to the target and compiled.
The Swift file doesn’t seem to register or expose any methods to Angular.
I even tried adding the code without using a plugin at all — just creating a Swift class and using it via the AppDelegate, but it still doesn't expose any callable methods.
My Swift code (RtspVlcPlugin.swift):
import Capacitor
import MobileVLCKit
@objc(RtspVlcPlugin)
public class RtspVlcPlugin: CAPPlugin, VLCMediaPlayerDelegate {
var mediaPlayer: VLCMediaPlayer?
var containerView: UIView?
var spinner: UIActivityIndicatorView?
@objc func iniciar(_ call: CAPPluginCall) {
guard
let urlStr = call.getString("url"),
let x = call.getDouble("x"),
let y = call.getDouble("y"),
let w = call.getDouble("width"),
let h = call.getDouble("height"),
let url = URL(string: urlStr)
else {
call.reject("Missing parameters")
return
}
DispatchQueue.main.async {
self.containerView?.removeFromSuperview()
let cont = UIView(frame: CGRect(x: x, y: y, width: w, height: h))
cont.backgroundColor = .black
cont.layer.cornerRadius = 16
cont.clipsToBounds = true
let sp = UIActivityIndicatorView(style: .large)
sp.center = CGPoint(x: w/2, y: h/2)
sp.color = .white
sp.startAnimating()
cont.addSubview(sp)
self.spinner = sp
self.containerView = cont
self.bridge?.viewController?.view.addSubview(cont)
let player = VLCMediaPlayer()
player.delegate = self
player.drawable = cont
player.media = VLCMedia(url: url)
self.mediaPlayer = player
player.play()
call.resolve()
}
}
@objc func cerrar(_ call: CAPPluginCall) {
DispatchQueue.main.async {
self.mediaPlayer?.stop()
self.mediaPlayer = nil
self.spinner?.stopAnimating()
self.spinner?.removeFromSuperview()
self.spinner = nil
self.containerView?.removeFromSuperview()
self.containerView = nil
call.resolve()
}
}
public func mediaPlayerStateChanged(_ aNotification: Notification!) {
guard let player = mediaPlayer,
player.state == .playing,
let sp = spinner else { return }
DispatchQueue.main.async {
sp.stopAnimating()
sp.removeFromSuperview()
self.spinner = nil
}
}
}
In the Angular project, I’m using the plugin by manually registering it with registerPlugin from @capacitor/core. Specifically, in the service where I need it, I do the following:
import { registerPlugin } from '@capacitor/core';
const RtspVlcPlugin: any = registerPlugin('RtspVlcPlugin');
After this, I try to call the methods defined in the iOS plugin, like RtspVlcPlugin.iniciar({ ... }), but I get an UNIMPLEMENTED error, which suggests that the plugin is not exposing its methods properly to the Angular/Capacitor environment. That makes me believe the problem lies in how the Swift file is integrated or registered, rather than how it is used from Angular.
I’d appreciate any guidance on how to properly expose a Swift-based Capacitor plugin’s methods so that they are accessible from Angular. Is there any additional registration step or metadata I might be missing on the iOS side?