JavaScript köprü API'si
Web Bluetooth
navigator.bluetooth yapısı yerel olarak yanıtlanır; böylece Chrome için yazılmış bir sayfa değişmeden çalışır.
wbConnect köprü#
window.WebToApk.wbConnect(requestId: String, deviceId: String)
WebBluetoothPolyfill için ham aktarım katmanı. Bir sayfa bunları doğrudan çağırmaz; tarayıcıda yapacağı gibi navigator.bluetooth'u çağırır.
Kendi başına değil, grubu Web Bluetooth (navigator.bluetooth) tarafından açıklanır.
Örnek
device.gatt.connect() arkasındaki iç aktarım. Sayfalar navigator.bluetooth kullanır; bunu doğrudan çağırmayın.
Döndürür: (gatt.connect() aracılığıyla) cihazın hizmetleri keşfedildikten sonra BluetoothRemoteGATTServer Promise'i. Gerekir: Bluetooth (kodunuz şunu andığında ZIP veya HTML derlemesi tarafından açılır: navigator.bluetooth).
async function connectAndList(device) {
try {
var server = await device.gatt.connect();
var services = await server.getPrimaryServices();
services.forEach(function (s) { console.log('service', s.uuid); });
return server;
} catch (err) {
showStatus('Could not connect: ' + err.message); // NetworkError, NotFoundError
return null;
}
}Cihaz koptuğunda yeniden bağlanın. Aynı cihazda connect() işlevini yeniden çağırmak çalışır:
device.addEventListener('gattserverdisconnected', async function () {
showStatus('Reconnecting...');
try { await connectAndList(device); showStatus('Connected'); } catch (e) {}
});İki sensöre aynı anda bağlanın, örneğin bir nabız bandı ve bir güç ölçer:
async function connectBoth(hrDevice, powerDevice) {
var servers = await Promise.all([hrDevice.gatt.connect(), powerDevice.gatt.connect()]);
var hr = await servers[0].getPrimaryService('heart_rate');
var power = await servers[1].getPrimaryService('cycling_power');
return {
heartRate: await hr.getCharacteristic('heart_rate_measurement'),
power: await power.getCharacteristic('cycling_power_measurement')
};
}Notlar: Ham imza wbConnect(requestId, deviceId). Zaten bağlı bir cihaza bağlanmak hemen yeniden çözülür. getPrimaryService(s), connect() tamamlanmadan önce NetworkError ile reddedilir. Aynı anda birkaç cihaz bağlanabilir.
wbDisconnect köprü#
window.WebToApk.wbDisconnect(deviceId: String)
WebBluetoothPolyfill için ham aktarım katmanı. Bir sayfa bunları doğrudan çağırmaz; tarayıcıda yapacağı gibi navigator.bluetooth'u çağırır.
Kendi başına değil, grubu Web Bluetooth (navigator.bluetooth) tarafından açıklanır.
Örnek
device.gatt.disconnect() (ve device.forget()) arkasındaki dahili aktarım katmanı. Sayfalar navigator.bluetooth kullanır; bunu doğrudan çağırmayın.
Döndürür: hiçbir şey (disconnect() web standardında olduğu gibi eşzamanlıdır). Ardından cihaz gattserverdisconnected olayını tetikler. Gerektirir: Bluetooth (kodunuz şunu andığında ZIP veya HTML derlemesi tarafından açılır: navigator.bluetooth).
var device = null; // from navigator.bluetooth.requestDevice(...)
document.getElementById('stop').addEventListener('click', function () {
if (device && device.gatt.connected) device.gatt.disconnect();
});
// Fires for your own disconnect() and when the device goes away by itself.
function watch(dev) {
dev.addEventListener('gattserverdisconnected', function () {
showStatus('Disconnected from ' + (dev.name || dev.id));
});
}Kendi Durdur işleminizi, sensörün menzil dışına çıkmasından ayırın ve yalnızca ikinci durumda yeniden bağlanın:
var userStopped = false;
function stopSession(device) {
userStopped = true;
if (device.gatt.connected) device.gatt.disconnect();
}
function watchDrops(device) {
device.addEventListener('gattserverdisconnected', function () {
if (userStopped) { userStopped = false; showStatus('Session ended'); return; }
showStatus('Sensor out of range, reconnecting...');
device.gatt.connect()
.then(resubscribe) // your code: get the characteristics, startNotifications()
.catch(function () { showStatus('Could not reconnect'); });
});
}Bir "Sensörü kaldır" düğmesi: forget() bağlantıyı keser ve cihazı bırakır, ardından gattserverdisconnected gelmez:
var device = null; // from navigator.bluetooth.requestDevice(...)
document.getElementById('forget').addEventListener('click', async function () {
if (!device) return;
await device.forget();
device = null;
showStatus('Sensor removed. Tap Connect to pick one again.');
});Notlar: Ham imza wbDisconnect(deviceId). Bağlantı kesildikten sonra eski hizmet ve özellik nesneleri bildirim almayı bırakır; bir sonraki connect() sonrasında onları yeniden alın ve startNotifications() işlevini yeniden çağırın. Uygulama kapandığında her bağlantıyı bırakır.
wbGetCharacteristics köprü#
window.WebToApk.wbGetCharacteristics(requestId: String, deviceId: String, service: String)
WebBluetoothPolyfill için ham aktarım katmanı. Bir sayfa bunları doğrudan çağırmaz; tarayıcıda yapacağı gibi navigator.bluetooth'u çağırır.
Kendi başına değil, grubu Web Bluetooth (navigator.bluetooth) tarafından açıklanır.
Örnek
service.getCharacteristic(uuid) ve service.getCharacteristics() arkasındaki iç aktarım. Sayfalar navigator.bluetooth kullanır; bunu doğrudan çağırmayın.
Döndürür: (hizmet aracılığıyla) bir BluetoothRemoteGATTCharacteristic Promise'i veya her biri uuid ve properties ile (read, write, writeWithoutResponse, notify, indicate, broadcast, authenticatedSignedWrites) bunların bir dizisi. Gerekir: Bluetooth (kodunuz şunu andığında ZIP veya HTML derlemesi tarafından açılır: navigator.bluetooth).
async function describe(server) {
var service = await server.getPrimaryService('heart_rate');
// One characteristic, by standard name, 16-bit number or full UUID:
var measurement = await service.getCharacteristic('heart_rate_measurement'); // same as 0x2a37
// All of them:
var list = await service.getCharacteristics();
list.forEach(function (c) {
var p = c.properties;
console.log(c.uuid, p.read ? 'read' : '', p.write ? 'write' : '', p.notify ? 'notify' : '');
});
return measurement;
}UUID'lerini koda sabit yazmak yerine, özel bir servisin karakteristiklerini yapabildikleri işe göre bulun:
async function findSerialPipes(server) {
var svc = await server.getPrimaryService('0000ffe0-0000-1000-8000-00805f9b34fb');
var list = await svc.getCharacteristics();
var incoming = list.find(function (c) { return c.properties.notify || c.properties.indicate; });
var outgoing = list.find(function (c) { return c.properties.write || c.properties.writeWithoutResponse; });
if (!incoming || !outgoing) throw new Error('This device does not look like a serial adapter');
return { incoming: incoming, outgoing: outgoing };
}İsteğe bağlı bir karakteristiği okuyun ve NotFoundError hatasını "bu cihazda yok" olarak değerlendirin:
var LOCATIONS = ['Other', 'Chest', 'Wrist', 'Finger', 'Hand', 'Ear lobe', 'Foot'];
async function sensorLocation(server) {
var hr = await server.getPrimaryService('heart_rate');
try {
var chr = await hr.getCharacteristic('body_sensor_location'); // 0x2a38, optional in the spec
var v = await chr.readValue();
return LOCATIONS[v.getUint8(0)] || 'Unknown';
} catch (err) {
if (err.name === 'NotFoundError') return null; // this strap does not report it
throw err;
}
}Notlar: Ham imza wbGetCharacteristics(requestId, deviceId, service). Servisin sahip olmadığı bir UUID NotFoundError ile reddedilir; bilinmeyen bir ad TypeError hatası verir (özel karakteristikler için tam bir UUID verin). Liste servis başına bir kez alınır, sonra yeniden kullanılır.
wbIsAvailable köprü#
window.WebToApk.wbIsAvailable(): Boolean
getAvailability(): telefonda Bluetooth OLUP OLMADIĞI (Chrome'un yanıtı), açık olup olmadığı değil. requestDevice(), kullanıcıdan açmasını ister; yalnızca kapalıyken false yanıtı vermek, önce kontrol eden sayfaların ("if (!await getAvailability())") "Bluetooth desteklenmiyor" demesine ve o isteme hiç ulaşmamasına yol açıyordu (fitness raporu 2026-10-03).
Örnek
navigator.bluetooth.getAvailability() arkasındaki iç aktarım. Sayfalar navigator.bluetooth kullanır; bunu doğrudan çağırmayın.
Döndürür: (getAvailability() aracılığıyla) derlemede Bluetooth varsa ve telefonun Bluetooth'u açıksa true, aksi halde false Promise'i. Gerekir: Bluetooth (kodunuz şunu andığında ZIP veya HTML derlemesi tarafından açılır: navigator.bluetooth).
async function updateBluetoothHint() {
var hint = document.getElementById('bt-hint');
if (!navigator.bluetooth) { hint.textContent = 'Bluetooth is not available in this app.'; return; }
var on = await navigator.bluetooth.getAvailability();
hint.textContent = on ? '' : 'Turn on Bluetooth to connect your sensor.';
}
document.addEventListener('visibilitychange', function () {
if (!document.hidden) updateBluetoothHint();
});Bağlan düğmesini yalnızca Bluetooth açıkken etkinleştirin ve kullanıcı uygulamaya her döndüğünde yeniden kontrol edin:
async function refreshConnectButton() {
var btn = document.getElementById('connect');
if (!navigator.bluetooth) { btn.hidden = true; return; }
btn.disabled = !(await navigator.bluetooth.getAvailability());
}
window.addEventListener('load', refreshConnectButton);
document.addEventListener('visibilitychange', function () {
if (!document.hidden) refreshConnectButton();
});Seçiciyi açmadan önce, sonrasında bir NotFoundError yerine net bir "Bluetooth kapalı" mesajı verin:
document.getElementById('scan').addEventListener('click', async function () {
if (!navigator.bluetooth) { showStatus('Bluetooth is not available in this app.'); return; }
if (!(await navigator.bluetooth.getAvailability())) {
showStatus('Bluetooth is off. Turn it on, then tap Scan again.');
return;
}
try {
var device = await navigator.bluetooth.requestDevice({ acceptAllDevices: true });
showStatus('Picked ' + (device.name || device.id));
} catch (err) {
showStatus(err.name === 'NotFoundError' ? 'No device chosen.' : err.message);
}
});Notlar: Ham imza wbIsAvailable(): Boolean (eşzamanlı). Yalnızca bağdaştırıcıyı kontrol eder - hiçbir izin istemez. Web standardının availabilitychanged olayı tetiklenmez, bu yüzden sayfa görünür olduğunda yeniden kontrol edin.
wbNotify köprü#
window.WebToApk.wbNotify(
WebBluetoothPolyfill için ham aktarım katmanı. Bir sayfa bunları doğrudan çağırmaz; tarayıcıda yapacağı gibi navigator.bluetooth'u çağırır.
Kendi başına değil, grubu Web Bluetooth (navigator.bluetooth) tarafından açıklanır.
Örnek
characteristic.startNotifications() ve stopNotifications() arkasındaki iç aktarım. Sayfalar navigator.bluetooth kullanır; bunu doğrudan çağırmayın.
Döndürür: (özellik aracılığıyla) özelliğin kendisinin bir Promise'i. Her yeni değer, üzerinde characteristicvaluechanged tetikler; değer event.target.value içindedir (bir DataView). Gerekir: Bluetooth (kodunuz şunu andığında ZIP veya HTML derlemesi tarafından açılır: navigator.bluetooth).
var cadenceChr = null;
async function startCadence(server) {
var svc = await server.getPrimaryService('running_speed_and_cadence');
cadenceChr = await svc.getCharacteristic('rsc_measurement');
cadenceChr.addEventListener('characteristicvaluechanged', onRsc);
await cadenceChr.startNotifications();
}
function onRsc(e) {
var v = e.target.value;
var kmh = v.getUint16(1, true) / 256 * 3.6;
var spm = v.getUint8(3);
show('run', kmh.toFixed(1) + ' km/h, ' + spm + ' steps/min');
}
async function stopCadence() {
if (!cadenceChr) return;
cadenceChr.removeEventListener('characteristicvaluechanged', onRsc);
try { await cadenceChr.stopNotifications(); } catch (e) {}
}Ölçümü yalnızca indication destekleyen bir termometreye aynı şekilde abone olunur; burada oncharacteristicvaluechanged özelliği üzerinden:
async function watchThermometer(server) {
var svc = await server.getPrimaryService('health_thermometer');
var chr = await svc.getCharacteristic('temperature_measurement');
chr.oncharacteristicvaluechanged = function (e) {
var v = e.target.value;
var mantissa = v.getUint32(1, true) & 0x00ffffff; // IEEE-11073 FLOAT
if (mantissa & 0x800000) mantissa -= 0x1000000;
var fahrenheit = v.getUint8(0) & 1;
show('temp', (mantissa * Math.pow(10, v.getInt8(4))).toFixed(1) + (fahrenheit ? ' °F' : ' °C'));
};
await chr.startNotifications();
}Seri tarzı bir cihazdan metin satırları alın; bir satırı ortadan bölen bildirimleri birleştirin:
async function listenForLines(server, onLine) {
var uart = await server.getPrimaryService('6e400001-b5a3-f393-e0a9-e50e24dcca9e');
var tx = await uart.getCharacteristic('6e400003-b5a3-f393-e0a9-e50e24dcca9e');
if (!tx.properties.notify && !tx.properties.indicate) throw new Error('This device does not stream data');
var decoder = new TextDecoder(), buffer = '';
tx.addEventListener('characteristicvaluechanged', function (e) {
buffer += decoder.decode(e.target.value, { stream: true });
var lines = buffer.split('\n');
buffer = lines.pop();
lines.forEach(onLine);
});
await tx.startNotifications();
return tx;
}Notlar: Ham imza wbNotify(requestId, deviceId, service, characteristic, enable). Yalnızca gösterge (indication) destekleyen bir özellik otomatik olarak göstergelerle abone olunur. Bildirim veremeyen bir özellik NotSupportedError ile reddedilir. oncharacteristicvaluechanged = fn de çalışır. Bağlantı kesildikten sonra yeniden abone olun.
wbRead köprü#
window.WebToApk.wbRead(requestId: String, deviceId: String, service: String, characteristic: String)
WebBluetoothPolyfill için ham aktarım katmanı. Bir sayfa bunları doğrudan çağırmaz; tarayıcıda yapacağı gibi navigator.bluetooth'u çağırır.
Kendi başına değil, grubu Web Bluetooth (navigator.bluetooth) tarafından açıklanır.
Örnek
characteristic.readValue() arkasındaki iç aktarım. Sayfalar navigator.bluetooth kullanır; bunu doğrudan çağırmayın.
Döndürür: (readValue() aracılığıyla) bir DataView Promise'i; characteristic.value de güncellenir. Gerekir: Bluetooth (kodunuz şunu andığında ZIP veya HTML derlemesi tarafından açılır: navigator.bluetooth).
async function readInfo(server) {
try {
var battery = await server.getPrimaryService('battery_service');
var level = await (await battery.getCharacteristic('battery_level')).readValue();
show('battery', level.getUint8(0) + '%');
var info = await server.getPrimaryService('device_information');
var maker = await (await info.getCharacteristic('manufacturer_name_string')).readValue();
show('maker', new TextDecoder().decode(maker));
} catch (err) {
// NotFoundError: the device has no such service/characteristic
// NotSupportedError: read rejected by the device NetworkError: not connected / read failed
show('info', err.message);
}
}Yalnızca okunabilen bir sensörü yoklayın; burada standart Temperature karakteristiği (0x2a6e, derecenin yüzde biri cinsinden):
var pollTimer = null;
async function startTemperaturePolling(server) {
var env = await server.getPrimaryService('environmental_sensing');
var temp = await env.getCharacteristic(0x2a6e);
pollTimer = setInterval(async function () {
try {
var v = await temp.readValue();
show('temp', (v.getInt16(0, true) / 100).toFixed(1) + ' °C');
} catch (err) {
clearInterval(pollTimer); // NetworkError once the sensor is gone
show('temp', err.message);
}
}, 5000);
}Birkaç okumayı aynı anda başlatarak bir "Bu cihaz hakkında" panelini doldurun; sizin için birbiri ardına çalışırlar:
async function readDeviceInfo(server) {
var info = await server.getPrimaryService('device_information');
var names = ['model_number_string', 'serial_number_string', 'firmware_revision_string'];
var decoder = new TextDecoder();
var results = await Promise.allSettled(names.map(async function (name) {
var chr = await info.getCharacteristic(name);
return decoder.decode(await chr.readValue());
}));
results.forEach(function (r, i) {
show(names[i], r.status === 'fulfilled' ? r.value : '-'); // missing ones reject with NotFoundError
});
}Notlar: Ham imza wbRead(requestId, deviceId, service, characteristic). Bir cihazdaki okuma, yazma ve bildirim değişiklikleri, çağırdığınız sırayla birbiri ardına çalışır; böylece arada beklemeden birkaçını art arda başlatabilirsiniz.
wbRequestDevice köprü#
window.WebToApk.wbRequestDevice(requestId: String, optionsJson: String)
WebBluetoothPolyfill için ham aktarım katmanı. Bir sayfa bunları doğrudan çağırmaz; tarayıcıda yapacağı gibi navigator.bluetooth'u çağırır.
Kendi başına değil, grubu Web Bluetooth (navigator.bluetooth) tarafından açıklanır.
Örnek
navigator.bluetooth.requestDevice(options) arkasındaki iç aktarım: uygulamanın cihaz seçicisini gösterir. Sayfalar navigator.bluetooth.requestDevice kullanır; bunu doğrudan çağırmayın.
Döndürür: (requestDevice aracılığıyla) bir BluetoothDevice {id, name, gatt} Promise'i. Gerekir: Bluetooth (kodunuz navigator.bluetooth ifadesini andığında ZIP veya HTML derlemesi tarafından açılır) ve ilk kullanımda sorulan Yakındaki cihazlar izni.
document.getElementById('pick').addEventListener('click', async function () {
if (!navigator.bluetooth) { showStatus('Bluetooth is not available in this app.'); return; }
try {
var device = await navigator.bluetooth.requestDevice({
filters: [{ services: ['cycling_power'] }, { namePrefix: 'KICKR' }],
optionalServices: ['battery_service']
});
showStatus('Picked ' + (device.name || device.id));
} catch (err) {
if (err.name === 'NotFoundError') showStatus('No device chosen.'); // also: Bluetooth off
else showStatus(err.name + ': ' + err.message); // SecurityError = permission
}
});Filtrelemek yerine yakındaki tüm cihazları listelemek için: requestDevice({ acceptAllDevices: true }).
Özel bir cihazı tam adı veya ad önekiyle seçin; bağlandıktan sonra kullanılabilmesi için kendi 128 bitlik servisini listeleyin:
async function pickLamp() {
try {
return await navigator.bluetooth.requestDevice({
filters: [{ name: 'Desk Lamp' }, { namePrefix: 'LAMP-' }], // either one matches
optionalServices: ['0000ffe0-0000-1000-8000-00805f9b34fb']
});
} catch (err) {
if (err.name === 'SecurityError') showStatus('Allow Nearby devices to find your lamp.');
else if (err.name !== 'NotFoundError') showStatus(err.message); // NotFoundError = cancelled
return null;
}
}Cihazı oturum başına bir kez isteyin ve sonraki dokunuşlarda yeniden kullanın (getDevices() kullanılamaz, bu yüzden aldığınız nesneyi saklayın):
var scale = null;
document.getElementById('weigh').addEventListener('click', async function () {
if (!navigator.bluetooth) { showStatus('Bluetooth is not available in this app.'); return; }
try {
if (!scale) {
scale = await navigator.bluetooth.requestDevice({
filters: [{ services: ['weight_scale'], namePrefix: 'MI' }] // both keys must match
});
}
var server = await scale.gatt.connect();
var svc = await server.getPrimaryService('weight_scale');
var chr = await svc.getCharacteristic('weight_measurement');
chr.addEventListener('characteristicvaluechanged', onWeight);
await chr.startNotifications();
} catch (err) {
showStatus(err.name + ': ' + err.message);
}
});Notlar: Ham imza wbRequestDevice(requestId, optionsJson); yanıt sayfaya değil, polyfill'e döner. requestDevice işlevini bir dokunuştan çağırın. Filtreler services (reklam edilmeli), name (tam eşleşme) ve namePrefix kullanır; bir filtre tüm anahtarları eşleştiğinde eşleşir ve cihaz herhangi bir filtre eşleştiğinde eşleşir. Ne filters ne de acceptAllDevices yoksa → TypeError. Seçiciyi iptal etmek NotFoundError ile reddeder. Seçici 30 saniye tarar. device.id cihazın Bluetooth adresidir.
wbWrite köprü#
window.WebToApk.wbWrite(
WebBluetoothPolyfill için ham aktarım katmanı. Bir sayfa bunları doğrudan çağırmaz; tarayıcıda yapacağı gibi navigator.bluetooth'u çağırır.
Kendi başına değil, grubu Web Bluetooth (navigator.bluetooth) tarafından açıklanır.
Örnek
characteristic.writeValue(), writeValueWithResponse() ve writeValueWithoutResponse() arkasındaki iç aktarım. Sayfalar navigator.bluetooth kullanır; bunu doğrudan çağırmayın.
Döndürür: (karakteristik aracılığıyla) undefined değerinin bir Promise'ini. Gerektirir: Bluetooth (kodunuz şunu andığında ZIP veya HTML derlemesi tarafından açılır: navigator.bluetooth).
Yanıtlı (writeValue da aynıdır): cihaz yazmayı onayladığında tamamlanır.
async function setTargetPower(server, watts) {
var ftms = await server.getPrimaryService('fitness_machine');
var cp = await ftms.getCharacteristic('00002ad9-0000-1000-8000-00805f9b34fb'); // FTMS control point
await cp.writeValueWithResponse(new Uint8Array([0x00])); // request control
var cmd = new DataView(new ArrayBuffer(3));
cmd.setUint8(0, 0x05); // set target power
cmd.setInt16(1, watts, true);
await cp.writeValueWithResponse(cmd);
}Yanıtsız: daha hızlı, bir paketin kaybolmasının önemli olmadığı akışlar için.
async function sendText(characteristic, text) {
if (!characteristic.properties.writeWithoutResponse) throw new Error('This characteristic needs writeValue');
await characteristic.writeValueWithoutResponse(new TextEncoder().encode(text));
}Uzun bir metin komutunu 20 baytlık parçalar halinde gönderin. Uygulama cihazdan daha büyük bir paket boyutu istemez, bu yüzden tek yazmaya 20 bayt sığar:
async function sendLine(rx, text) {
var bytes = new TextEncoder().encode(text + '\n');
for (var i = 0; i < bytes.length; i += 20) {
await rx.writeValueWithoutResponse(bytes.subarray(i, i + 20));
}
}
// sendLine(rxCharacteristic, 'SET COLOR 255 120 0 BRIGHTNESS 80');Notlar: Ham imza wbWrite(requestId, deviceId, service, characteristic, valueBase64, withResponse). Değer bir ArrayBuffer, herhangi bir tipli dizi, bir DataView veya düz bir bayt dizisi olabilir; başka her şey TypeError hatası verir. Hatalar: NotSupportedError (yazma reddedildi), NetworkError (yazma başarısız oldu veya bağlı değil), NotFoundError.