Zum Hauptinhalt springen

Haptisches Feedback (iOS WebView)

#PinpollTools #Integration #UX

Tobias Oberascher avatar
Verfasst von Tobias Oberascher
Diese Woche aktualisiert

Überblick

Das Pinpoll-Widget löst haptisches Feedback über die Standardmethode navigator.vibrate in Browsern aus. Um jedoch native Haptik in mobilen Apps (iOS/Android) zu unterstützen, sendet das Widget strukturierte postMessage-Ereignisse, die auf der nativen Seite verarbeitet werden müssen (z. B. in einer React Native WebView).

Aufbau der postMessage

Das Widget sendet Nachrichten über window.postMessage im folgenden Format:

{  type: 'pinpoll-haptic',  vibrate: number | number[]}

Parameter:

  • type (string): Immer 'pinpoll-haptic', um die haptischen Ereignisse des Pinpoll-Widgets zu identifizieren.

  • vibrate (number oder array): Definiert das Vibrationsmuster, entsprechend der Struktur der Vibration API im Browser:

    • Eine einzelne Zahl (z. B. 50) → Vibriert für 50 ms.

    • Ein Array (z. B. [30, 20, 30]) → Vibriert für 30 ms, pausiert 20 ms, dann vibriert erneut 30 ms.

Implementieren des WebView Listeners

In einer nativen App (z. B. React Native) muss diese Nachricht manuell empfangen und verarbeitet werden:

window.addEventListener("message", function (event) {
try {
const data =
typeof event.data === "string" ? JSON.parse(event.data) : event.data
// Check for haptic feedback event
if (data.type === "pinpoll-haptic") {
// Forward message to native context if using ReactNativeWebView
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(JSON.stringify(data))
}
}
} catch (e) {
console.warn("Message forwarding error:", e)
}
})

Füge diesen Handler in der <WebView>-Komponente hinzu:

<WebView
source={{ uri: 'https://your-widget-url.com' }}
onMessage={handleMessage}
javaScriptEnabled
/>

Event Handling (React Native)

import * as Haptics from 'expo-haptics';
import * as Device from 'expo-device';
import { Vibration } from 'react-native';

export default function App() {
...
/**
* Handles messages from the WebView on the App level.
* @param {Object} event - The event object containing the message data.
* @returns {void}
*/
const handleMessage = (event) => {
try {
const data = JSON.parse(event.nativeEvent.data);
if (data.type === 'pinpoll-haptic') {
triggerHaptic(data.vibrate);
}
} catch (e) {
console.warn('Invalid message:', e);
}
};

/**
* Triggers haptic feedback or vibration based on the provided parameter.
* If the device is old (iPhone 6 or earlier, or iOS version < 13), it uses Vibration API.
* Otherwise, it uses Haptics API for better feedback.
* @param {number | number[]} param - A number representing the strength of the vibration or an array of patterns for sequential vibrations.
*/
const triggerHaptic = async (param) => {
try {
const isOld = Device.modelName?.includes('iPhone 6') || parseFloat(Device.osVersion) < 13;
console.log('Device:', Device.modelName, 'OS Version:', Device.osVersion, 'Using'+ (isOld ? ' Vibration' : ' Haptics'));

if (Array.isArray(param)) {
let i = 0;
const pattern = param;
const loop = () => {
if (i >= pattern.length) return;
const isVibrate = i % 2 === 0;
if (isVibrate) {
console.log('Vibrating MEDIUM with pattern:', pattern[i]);
if (isOld) {
Vibration.vibrate(pattern[i]);
}
else { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); }
}
setTimeout(loop, pattern[i]);
i++;
};
loop();
} else {
const strength = +param || 50; // Default to 50 if not a number
if (isOld) {
if (strength > 20) {
console.log('Vibrating with strength:', strength);
Vibration.vibrate(strength);
} else {
console.log('Too subtle vibration, cant vibrate with strength:', strength);
}

} else {
if (strength < 20) {
console.log('Vibrating LIGHT with strength:', strength);
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
} else if (strength < 50) {
console.log('Vibrating MEDIUM with strength:', strength);
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
} else {
console.log('Vibrating HEAVY with strength:', strength);
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
}
}
}
} catch (e) {
console.warn('triggerHaptic failed', e);
Vibration.vibrate(50);
}
};
}
Hat dies deine Frage beantwortet?