import AudioToolbox import CoreHaptics import Flutter import UIKit public class VibrationPluginSwift: NSObject, FlutterPlugin { #if targetEnvironment(simulator) private let isDevice = false #else private let isDevice = true #endif private static let feedbackGenerator = UIImpactFeedbackGenerator(style: .light) @available(iOS 13.0, *) public static var engine: CHHapticEngine? public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel(name: "vibration", binaryMessenger: registrar.messenger()) let instance = VibrationPluginSwift() if #available(iOS 13.0, *) { VibrationPluginSwift.createEngine() } feedbackGenerator.prepare() registrar.addMethodCallDelegate(instance, channel: channel) } @available(iOS 13.0, *) public static func createEngine() { // Create and configure a haptic engine. do { VibrationPluginSwift.engine = try CHHapticEngine() } catch { print("Engine creation error: \(error)") return } if VibrationPluginSwift.engine == nil { print("Failed to create engine!") } // The stopped handler alerts you of engine stoppage due to external causes. VibrationPluginSwift.engine?.stoppedHandler = { reason in print("The engine stopped for reason: \(reason.rawValue)") } // The reset handler provides an opportunity for your app to restart the engine in case of failure. VibrationPluginSwift.engine?.resetHandler = { // Try restarting the engine. print("The engine reset --> Restarting now!") do { try VibrationPluginSwift.engine?.start() } catch { print("Failed to restart the engine: \(error)") } } } private func supportsHaptics() -> Bool { if #available(iOS 13.0, *) { return CHHapticEngine.capabilitiesForHardware().supportsHaptics } return false; } @available(iOS 13.0, *) private func playPattern(myArgs: [String: Any], pattern: [Int]) -> Void { // Get event parameters, if any var params: [CHHapticEventParameter] = [] //var amplitudes: [Int] = [] let amplitudes = myArgs["intensities"] as! [Int] // Create haptic events var hapticEvents: [CHHapticEvent] = [] var i: Int = 0 var rel: Double = 0.0 while i < pattern.count { // Get intensity parameter, if any if (i < amplitudes.count) { if(amplitudes[i] != 0) { let p = CHHapticEventParameter(parameterID: .hapticIntensity, value: Float(Double(amplitudes[i]) / 255.0)) // Get wait time and duration let duration = Double(pattern[i]) / 1000.0 // Create haptic event let e = CHHapticEvent( eventType: .hapticContinuous, parameters: [p], relativeTime: rel, duration: duration ) hapticEvents.append(e) // Add duration to relative time rel += duration } else { let waitTime = Double(pattern[i]) / 1000.0 rel += waitTime } } i += 1 } // Try to play engine do { if let engine = VibrationPluginSwift.engine { let patternToPlay = try CHHapticPattern(events: hapticEvents, parameters: []) let player = try engine.makePlayer(with: patternToPlay) try engine.start() try player.start(atTime: 0) } } catch { print("Failed to play pattern: \(error.localizedDescription).") } } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "hasVibrator": result(isDevice) case "hasAmplitudeControl": result(isDevice) case "hasCustomVibrationsSupport": result(supportsHaptics()) case "vibrate": VibrationPluginSwift.feedbackGenerator.impactOccurred() result(isDevice) // guard let args = call.arguments else { // result(false) // return // } // // guard let myArgs = args as? [String: Any] else { // AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) // result(true) // return // } // // guard let pattern = myArgs["pattern"] as? [Int] else { // AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) // result(true) // return // } // // if pattern.count == 0 { // AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) // result(true) // return // } // // assert(pattern.count % 2 == 0, "Pattern must have even number of elements!") // // if !supportsHaptics() { // AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) // result(true) // return // } // // if #available(iOS 13.0, *) { // playPattern(myArgs: myArgs, pattern: pattern) // } // // result(isDevice) case "cancel": result(nil) default: result(FlutterMethodNotImplemented) } } }