Wir müssen auf die Karte klicken, um die Audiodatei abzuspielen.
Legen Sie zuerst die MP3‑Audiodatei in das Verzeichnis www/audio ab
Da es sich um ein Demoprojekt handelt, reicht es aus, die Datei b.mp3 in diesem Ordner abzulegen.

Methode 1 – Wiedergabe über HTML5
Die Audiowiedergabe erfolgt über das von WebView unterstützte HTML5‑Audio‑Interface, es sind keine Plugins erforderlich
Passen Sie den Inhalt von main.js wie folgt an
// Daten der vietnamesischen Konsonanten
const consonants = [
{char: "b", pronounce: "/ɓ/", desc: "Implosiver bilabial‑Verschlusslaut"},
{char: "c", pronounce: "/k/", desc: "Harter velarer Verschlusslaut"},
{char: "ch", pronounce: "/tɕ/", desc: "Palataler Affrikatlaut"},
{char: "d", pronounce: "/ɗ/", desc: "Implosiver alveolarer Verschlusslaut"},
{char: "đ", pronounce: "/ɗ/", desc: "Alveolarer Implosivlaut"},
{char: "g", pronounce: "/ɣ/", desc: "Velarer Reibelaut"},
{char: "gh", pronounce: "/ɣ/", desc: "Verwendet vor e, i"},
{char: "h", pronounce: "/h/", desc: "Glottaler Reibelaut"},
{char: "k", pronounce: "/k/", desc: "Harter velarer Verschlusslaut"},
{char: "kh", pronounce: "/x/", desc: "Harter velarer Reibelaut"},
{char: "l", pronounce: "/l/", desc: "Alveolarer Laterallaut"},
{char: "m", pronounce: "/m/", desc: "Bilabialer Nasallaut"},
{char: "n", pronounce: "/n/", desc: "Alveolarer Nasallaut"},
{char: "ng", pronounce: "/ŋ/", desc: "Weicher velarer Nasallaut"},
{char: "ngh", pronounce: "/ŋ/", desc: "Verwendet vor e,i"},
{char: "nh", pronounce: "/ɲ/", desc: "Palataler Nasallaut"},
{char: "p", pronounce: "/p/", desc: "Nicht‑implosiver bilabialer Verschlusslaut"},
{char: "ph", pronounce: "/f/", desc: "Labiodentaler Reibelaut"},
{char: "q", pronounce: "/kw/", desc: "Steht immer in Kombination mit u"},
{char: "r", pronounce: "/r/", desc: "Alveolarer Vibrationslaut"},
{char: "s", pronounce: "/s/", desc: "Alveolarer Reibelaut"},
{char: "t", pronounce: "/t/", desc: "Alveolarer Verschlusslaut"},
{char: "th", pronounce: "/θ/", desc: "Dentaler Reibelaut"},
{char: "v", pronounce: "/v/", desc: "Labiodentaler Reibelaut"},
{char: "x", pronounce: "/s/", desc: "Alveolarer Reibelaut"}
];
let favList = JSON.parse(localStorage.getItem("vn_consonant_fav")) || [];
let currentAudio = null; // Globales Audio‑Objekt, um vorherige Wiedergabe zu stoppen
const gridEl = document.getElementById("consonant-grid");
const favGridEl = document.getElementById("favorite-grid");
const modal = document.getElementById("modal");
const modalChar = document.getElementById("modal-char");
const modalPro = document.getElementById("modal-pronounce");
const modalDesc = document.getElementById("modal-desc");
const btnFav = document.getElementById("btn-fav");
const closeModal = document.getElementById("close-modal");
let currentItem = null;
// ====================== FUNKTION ZUM MP3‑ABSPIELEN ======================
function playAudio(charName) {
// Laufende Audiodatei stoppen
if(currentAudio){
currentAudio.pause();
currentAudio.currentTime = 0;
}
// Audio‑Objekt erstellen
currentAudio = new Audio(`audio/${charName}.mp3`);
currentAudio.volume = 1;
currentAudio.play().catch(err=>{
console.log("Datei konnte nicht abgespielt werden: ", charName, err);
alert(`Audiodatei nicht gefunden: ${charName}.mp3`);
});
}
// Karten für Konsonanten rendern
function renderCards(){
gridEl.innerHTML = "";
consonants.forEach(item=>{
const div = document.createElement("div");
div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
div.onclick = ()=> {
playAudio(item.char); // Klick auf Karte spielt MP3 ab
openModal(item);
};
gridEl.appendChild(div);
})
}
// Favoritenseite rendern
function renderFav(){
favGridEl.innerHTML = "";
if(favList.length === 0){
favGridEl.innerHTML = `<p class="col-span-3 text-center text-gray-400 py-10">Keine Favoriten hinterlegt</p>`;
return;
}
favList.forEach(item=>{
const div = document.createElement("div");
div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
div.onclick = ()=> {
playAudio(item.char);
openModal(item);
};
favGridEl.appendChild(div);
})
}
// Detail‑Popup öffnen
function openModal(item){
currentItem = item;
modalChar.innerText = item.char;
modalPro.innerText = item.pronounce;
modalDesc.innerText = item.desc;
updateFavButton();
modal.classList.remove("hidden");
}
// Popup schließen
closeModal.onclick = ()=>{
modal.classList.add("hidden");
}
modal.onclick = (e)=>{
if(e.target === modal) modal.classList.add("hidden");
}
// Schalter zum Hinzufügen / Entfernen von Favoriten
function updateFavButton(){
const exist = favList.find(x=>x.char === currentItem.char);
btnFav.innerText = exist ? "Aus Favoriten entfernen" : "Zu Favoriten hinzufügen";
}
btnFav.onclick = ()=>{
const idx = favList.findIndex(x=>x.char === currentItem.char);
if(idx >=0) favList.splice(idx,1);
else favList.push(currentItem);
localStorage.setItem("vn_consonant_fav", JSON.stringify(favList));
updateFavButton();
renderFav();
}
// Seitenumschaltung über Tabs
const tabBtns = document.querySelectorAll(".tab-btn");
const pages = document.querySelectorAll(".page");
tabBtns.forEach(btn=>{
btn.onclick = ()=>{
const targetId = btn.dataset.target;
tabBtns.forEach(b=>{
b.classList.remove("tab-active");
b.querySelector("svg").classList.add("text-gray-500");
})
btn.classList.add("tab-active");
btn.querySelector("svg").classList.remove("text-gray-500");
pages.forEach(p=>p.classList.add("hidden"));
document.getElementById(targetId).classList.remove("hidden");
}
})
document.addEventListener("DOMContentLoaded", ()=>{
renderCards();
renderFav();
})
document.addEventListener("deviceready", ()=>{
console.log("Cordova ist bereit");
}, false);Code-Sprache: JavaScript (javascript)
Methode 2 – Wiedergabe über Plugin
Wiedergabe mit dem Cordova‑Plugin cordova‑plugin‑media
Plugin installieren
cordova plugin add cordova-plugin-media
Ausgabe während der Ausführung
D:\cordovademo\hello>cordova plugin add cordova-plugin-media
Installing "cordova-plugin-media" for android
Installing "cordova-plugin-file" for android
Subproject Path: CordovaLib
Subproject Path: app
The Android Persistent storage location now defaults to "Internal". Please check this plugin's README to see if your application needs any changes in its config.xml.
If this is a new application no changes are required.
If this is an update to an existing application that did not specify an "AndroidPersistentFileLocation" you may need to add:
"<preference name="AndroidPersistentFileLocation" value="Compatibility" />"
to config.xml in order for the application to find previously stored files.
Adding cordova-plugin-media to package.jsonCode-Sprache: HTML, XML (xml)
Funktion für die Audiowiedergabe austauschen
let mediaPlayer = null;
function playAudio(charName) {
// Alte Audiodatei stoppen
if(mediaPlayer){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
// Wichtig: Cordova‑Android‑Pfad www/audio/
const src = `audio/${charName}.mp3`;
mediaPlayer = new Media(src,
()=>{
// Ressourcen nach Ende der Wiedergabe freigeben
mediaPlayer.release();
mediaPlayer = null;
},
(err)=>{
console.error("Fehler bei der Audiowiedergabe", err);
}
);
mediaPlayer.play();
}Code-Sprache: JavaScript (javascript)
Ersetzen Sie damit die entsprechende Methode in der ursprünglichen main.js
// Daten der vietnamesischen Konsonanten
const consonants = [
{char: "b", pronounce: "/ɓ/", desc: "Implosiver bilabial‑Verschlusslaut"},
{char: "c", pronounce: "/k/", desc: "Harter velarer Verschlusslaut"},
{char: "ch", pronounce: "/tɕ/", desc: "Palataler Affrikatlaut"},
{char: "d", pronounce: "/ɗ/", desc: "Implosiver alveolarer Verschlusslaut"},
{char: "đ", pronounce: "/ɗ/", desc: "Alveolarer Implosivlaut"},
{char: "g", pronounce: "/ɣ/", desc: "Velarer Reibelaut"},
{char: "gh", pronounce: "/ɣ/", desc: "Verwendet vor e, i"},
{char: "h", pronounce: "/h/", desc: "Glottaler Reibelaut"},
{char: "k", pronounce: "/k/", desc: "Harter velarer Verschlusslaut"},
{char: "kh", pronounce: "/x/", desc: "Harter velarer Reibelaut"},
{char: "l", pronounce: "/l/", desc: "Alveolarer Laterallaut"},
{char: "m", pronounce: "/m/", desc: "Bilabialer Nasallaut"},
{char: "n", pronounce: "/n/", desc: "Alveolarer Nasallaut"},
{char: "ng", pronounce: "/ŋ/", desc: "Weicher velarer Nasallaut"},
{char: "ngh", pronounce: "/ŋ/", desc: "Verwendet vor e,i"},
{char: "nh", pronounce: "/ɲ/", desc: "Palataler Nasallaut"},
{char: "p", pronounce: "/p/", desc: "Nicht‑implosiver bilabialer Verschlusslaut"},
{char: "ph", pronounce: "/f/", desc: "Labiodentaler Reibelaut"},
{char: "q", pronounce: "/kw/", desc: "Steht immer in Kombination mit u"},
{char: "r", pronounce: "/r/", desc: "Alveolarer Vibrationslaut"},
{char: "s", pronounce: "/s/", desc: "Alveolarer Reibelaut"},
{char: "t", pronounce: "/t/", desc: "Alveolarer Verschlusslaut"},
{char: "th", pronounce: "/θ/", desc: "Dentaler Reibelaut"},
{char: "v", pronounce: "/v/", desc: "Labiodentaler Reibelaut"},
{char: "x", pronounce: "/s/", desc: "Alveolarer Reibelaut"}
];
let favList = JSON.parse(localStorage.getItem("vn_consonant_fav")) || [];
let currentAudio = null; // Globales Audio‑Objekt, um vorherige Wiedergabe zu stoppen
const gridEl = document.getElementById("consonant-grid");
const favGridEl = document.getElementById("favorite-grid");
const modal = document.getElementById("modal");
const modalChar = document.getElementById("modal-char");
const modalPro = document.getElementById("modal-pronounce");
const modalDesc = document.getElementById("modal-desc");
const btnFav = document.getElementById("btn-fav");
const closeModal = document.getElementById("close-modal");
let currentItem = null;
// ====================== FUNKTION ZUM MP3‑ABSPIELEN ======================
let mediaPlayer = null;
function playAudio(charName) {
// Alte Audiodatei stoppen
if(mediaPlayer){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
// Wichtig: Cordova‑Android‑Pfad www/audio/
const src = `audio/${charName}.mp3`;
mediaPlayer = new Media(src,
()=>{
// Ressourcen nach Ende der Wiedergabe freigeben
mediaPlayer.release();
mediaPlayer = null;
},
(err)=>{
console.error("Fehler bei der Audiowiedergabe", err);
}
);
mediaPlayer.play();
}
// Karten für Konsonanten rendern
function renderCards(){
gridEl.innerHTML = "";
consonants.forEach(item=>{
const div = document.createElement("div");
div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
div.onclick = ()=> {
playAudio(item.char); // Klick auf Karte spielt MP3 ab
openModal(item);
};
gridEl.appendChild(div);
})
}
// Favoritenseite rendern
function renderFav(){
favGridEl.innerHTML = "";
if(favList.length === 0){
favGridEl.innerHTML = `<p class="col-span-3 text-center text-gray-400 py-10">Keine Favoriten hinterlegt</p>`;
return;
}
favList.forEach(item=>{
const div = document.createElement("div");
div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
div.onclick = ()=> {
playAudio(item.char);
openModal(item);
};
favGridEl.appendChild(div);
})
}
// Detail‑Popup öffnen
function openModal(item){
currentItem = item;
modalChar.innerText = item.char;
modalPro.innerText = item.pronounce;
modalDesc.innerText = item.desc;
updateFavButton();
modal.classList.remove("hidden");
}
// Popup schließen
closeModal.onclick = ()=>{
modal.classList.add("hidden");
}
modal.onclick = (e)=>{
if(e.target === modal) modal.classList.add("hidden");
}
// Schalter zum Hinzufügen / Entfernen von Favoriten
function updateFavButton(){
const exist = favList.find(x=>x.char === currentItem.char);
btnFav.innerText = exist ? "Aus Favoriten entfernen" : "Zu Favoriten hinzufügen";
}
btnFav.onclick = ()=>{
const idx = favList.findIndex(x=>x.char === currentItem.char);
if(idx >=0) favList.splice(idx,1);
else favList.push(currentItem);
localStorage.setItem("vn_consonant_fav", JSON.stringify(favList));
updateFavButton();
renderFav();
}
// Seitenumschaltung über Tabs
const tabBtns = document.querySelectorAll(".tab-btn");
const pages = document.querySelectorAll(".page");
tabBtns.forEach(btn=>{
btn.onclick = ()=>{
const targetId = btn.dataset.target;
tabBtns.forEach(b=>{
b.classList.remove("tab-active");
b.querySelector("svg").classList.add("text-gray-500");
})
btn.classList.add("tab-active");
btn.querySelector("svg").classList.remove("text-gray-500");
pages.forEach(p=>p.classList.add("hidden"));
document.getElementById(targetId).classList.remove("hidden");
}
})
document.addEventListener("DOMContentLoaded", ()=>{
renderCards();
renderFav();
})
document.addEventListener("deviceready", ()=>{
console.log("Cordova ist bereit");
}, false);Code-Sprache: JavaScript (javascript)
Audio abspielen