PWA'nız için yeni ve yakında kullanıma sunulacak tarayıcı özelliklerini keşfedin: From Fugu With Love

1. Başlamadan önce

Progresif Web Uygulamaları (PWA'lar); HTML, CSS ve JavaScript gibi yaygın web teknolojileri kullanılarak oluşturulmuş, web üzerinden sunulan bir uygulama yazılımı türüdür. Standartlara uygun bir tarayıcı kullanan tüm platformlarda çalışacak şekilde tasarlanmıştır.

Bu codelab'de, temel bir PWA ile başlayıp daha sonra PWA'larınıza süper güçler kazandıracak yeni tarayıcı özelliklerini keşfedin 🦸.

Bu yeni tarayıcı özelliklerinin birçoğu kullanımdadır ve hâlâ standart hale getirilmiştir. Bu nedenle, bazen bunları kullanmak için tarayıcı flag'leri ayarlamanız gerekir.

Ön koşullar

Bu codelab için modern JavaScript'i, özellikle de vaatleri ve eşzamansız/beklemede aşina olmanız gerekir. Codelab'in tüm adımları tüm platformlarda desteklenmediğinden, elinizde başka bir cihazın (ör. Android telefon veya kodu düzenlediğiniz cihazdan farklı bir işletim sistemi kullanan dizüstü bilgisayar) olup olmadığını test etmek yararlıdır. Gerçek cihazlara alternatif olarak, Android simülatörü gibi simülasyon araçlarını veya mevcut cihazınızdan test yapmanızı sağlayan BrowserStack gibi online hizmetleri kullanmayı deneyebilirsiniz. Ayrıca, herhangi bir adımı atlamak için de kullanılan bu adımlar birbirine bağlı değildir.

Derlemeniz istenen nedir?

Bir tebrik kartı web uygulaması oluşturacaksınız. Ayrıca yeni ve yakında çıkacak tarayıcı özellikleri tüm modern tarayıcılarda faydalı olmaya devam edecek olsa da bu özelliklerin, uygulamanızı belirli tarayıcılarda gelişmiş bir deneyim sunacak şekilde nasıl geliştirebileceğini öğreneceksiniz.

Dosya sistemi erişimi, sistem panosu erişimi, kişi alma, düzenli arka plan senkronizasyonu, ekran uyanık kalma kilidi, paylaşım özellikleri gibi destek özelliklerini nasıl ekleyeceğinizi öğreneceksiniz.

Codelab'i inceledikten sonra, web uygulamalarınızı yeni tarayıcı özellikleriyle kademeli olarak nasıl iyileştireceğinizi daha iyi anlayacaksınız. aynı zamanda, uyumsuz tarayıcılara sahip olan kullanıcılarınızın alt grubuna da yükleme yükü yüklememiş ve en önemlisi, onları ilk olarak uygulamanızdan hariç tutacaktır.

Gerekenler

Şu anda tam olarak desteklenen tarayıcılar şunlardır:

Belirli bir Geliştirici kanalını kullanmanız önerilir.

2. Fugu Projesi

Progresif Web Uygulamaları (PWA); gelişmiş API'ler ile geliştirilip geliştirilmiştir. Gelişmiş özellikler, güvenilirlik ve yüklenebilirlik sağlarken web'de dünyanın her yerinde herkese ve her tür cihaza erişebilir.

Bu API'lerden bazıları son derece güçlüdür ve yanlış kullanılırsa bir şeyler ters gidebilir. Tıpkı fugu balığı gibi 🐡: Kestiğiniz güzel bir lezzet ama yarım kestiğiniz kesit de ölümcül olabilir ancak endişelenmeyin. Bu codelab'de hiçbir şey bozulmaz.

Bu nedenle, Web Capabilities projesinin (ilgili şirketlerin bu yeni API'leri geliştirdiği) dahili kod adı Project Fugu'dur.

Günümüzde zaten kullanılabilen web özellikleri, büyük ve küçük kurumların sadece tarayıcı tabanlı çözümlerden yararlanmasını sağlar. Bu da platforma özel rotadan genellikle daha düşük geliştirme maliyetleriyle daha hızlı dağıtıma olanak tanır.

3. Başlarken

İki tarayıcının herhangi birini indirin ve ardından hem Chrome hem de Edge'de çalışan about://flags konumuna giderek şu çalışma zamanı işaretini 🚩 ayarlayın:

  • #enable-experimental-web-platform-features

Etkinleştirdikten sonra tarayıcınızı yeniden başlatın.

PWA'nızı barındırmanıza olanak tanıdığı ve iyi bir editörü olduğu için Glitch platformunu kullanacaksınız. Glitch, GitHub'ın içe ve dışa aktarma işlemini de destekler. Bu nedenle, tedarikçi firma kilitli değildir. Uygulamayı denemek için fugu-paint.glitch.me adresine gidin. Codelab'de iyileştirebileceğiniz temel bir çizim uygulamasıdır.

Üzerinde "&";Google” yazan büyük bir tuvalin bulunduğu Fugueting Base PWA.

Uygulamayla oynaydıktan sonra, düzenleyebileceğiniz bir kopyayı oluşturmak için uygulamayı remiksleyin. remiksinizin URL'si ise glitch.com/edit/#!/bouncy-candytuft şeklinde olacaktır ("sahne-candytuft", sizin için başka bir URL olacaktır). Bu remiksa dünya genelinde doğrudan erişilebilir. Çalışmanızı kaydetmek için mevcut hesabınızda oturum açın veya Glitch'te yeni bir hesap oluşturun. Uygulamanızı "🕶 Göster" düğmesini tıklayarak görebilirsiniz. Barındırılan uygulamanın URL'si bouncy-candytuft.glitch.me şeklinde olur (üst düzey alan olarak .com yerine .me öğesine dikkat edin).

Artık uygulamanızı düzenlemeye ve iyileştirmeye hazırsınız. Değişiklik yaptığınızda uygulama yeniden yüklenir ve değişiklikleriniz doğrudan görünür hale gelir.

Bir HTML dokümanının düzenlenmesini gösteren reklam IDE'si.

İdeal olarak aşağıdaki görevlerin tamamlanması gerekir, ancak yukarıda belirtildiği gibi, uyumlu bir cihaza erişiminiz yoksa istediğiniz zaman bir adımı atlayabilirsiniz. Her görevin bir özelliğin ne kadar deneysel olduğu konusunda sizi uyaran 🐟, zararsız tatlı su balığı veya fugu balıklarının dikkatli olduğu 🐡 ile işaretlendiğini unutmayın.

Mevcut cihazlarda API'nin desteklenip desteklenmediğini görmek için Geliştirici Araçları'ndaki Console'u kontrol edin. Ayrıca, Glitch'i de kullanarak aynı uygulamayı farklı cihazlarda (ör. cep telefonunuzda ve masaüstü bilgisayarınızda) kolayca kontrol edebilirsiniz.

Geliştirici Araçları'nda Console'a kaydedilen API uyumluluğu.

4. 🐟 Web Paylaşımı API'si Desteği Ekleyin

En iyi çizimleri oluşturmak hiç kimseyi ilgilendirmeyecekse sıkıcıdır. Kullanıcılarınızın, çizimlerini dünyayla paylaşabilecekleri, tebrik kartı biçiminde bir özellik ekleyin.

Web Share API, dosya paylaşımını destekler. Hatırlayabileceğiniz üzere File yalnızca belirli bir Blob türüdür. Bu nedenle, share.mjs adlı dosyada paylaş düğmesini ve bir tuvalin içeriğini blob'a dönüştüren aşağıdaki işleve göre paylaşım işlevini ekleyen bir rahatlık işlevini toBlob() kullanın.

Bu yöntemi uyguladıysanız ancak düğmeyi görmüyorsanız tarayıcınız Web Share API'yi uygulamamaktadır.

import { shareButton, toBlob } from './script.mjs';

const share = async (title, text, blob) => {
  const data = {
    files: [
      new File([blob], 'fugu-greeting.png', {
        type: blob.type,
      }),
    ],
    title: title,
    text: text,
  };
  try {
    if (!navigator.canShare(data)) {
      throw new Error("Can't share data.", data);
    }
    await navigator.share(data);
  } catch (err) {
    console.error(err.name, err.message);
  }
};

shareButton.style.display = 'block';
shareButton.addEventListener('click', async () => {
  return share('Fugu Greetings', 'From Fugu With Love', await toBlob());
});

5. 🐟 Web Paylaşımı Hedef API'sı Desteği Ekleyin

Kullanıcılarınız artık uygulama kullanılarak oluşturulan tebrik kartlarını paylaşabilir. Ancak, kullanıcıların uygulamanızla resim paylaşmalarına ve bunları tebrik kartlarına dönüştürmelerine de izin verebilirsiniz. Bunun için Web Share Target API'yi kullanabilirsiniz.

Web Uygulaması Manifest'inde, uygulamaya ne tür dosyaları kabul edebileceğinizi ve bir veya daha fazla dosya paylaşıldığında tarayıcının hangi URL'yi çağıracağını bildirmeniz gerekir. manifest.webmanifest dosyasının altındaki alıntıda bu gösterilir.

{
  "share_target": {
    "action": "./share-target/",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "files": [
        {
          "name": "image",
          "accept": ["image/jpeg", "image/png", "image/webp", "image/gif"]
        }
      ]
    }
  }
}

Ardından hizmet çalışanı, alınan dosyalarla ilgilenir. ./share-target/ URL'si aslında mevcut değil, uygulama yalnızca fetch işleyicisinde işlem yapıyor ve ?share-target sorgu parametresini ekleyerek isteği kök URL'ye yönlendiriyor:

self.addEventListener('fetch', (fetchEvent) => {
  /* 🐡 Start Web Share Target */
  if (
    fetchEvent.request.url.endsWith('/share-target/') &&
    fetchEvent.request.method === 'POST'
  ) {
    return fetchEvent.respondWith(
      (async () => {
        const formData = await fetchEvent.request.formData();
        const image = formData.get('image');
        const keys = await caches.keys();
        const mediaCache = await caches.open(
          keys.filter((key) => key.startsWith('media'))[0],
        );
        await mediaCache.put('shared-image', new Response(image));
        return Response.redirect('./?share-target', 303);
      })(),
    );
  }
  /* 🐡 End Web Share Target */

  /* ... */
});

Uygulama yüklendiğinde, bu sorgu parametresinin ayarlanıp ayarlanmadığını kontrol eder. Ayarlanmışsa paylaşılan resmi tuvale çizer ve önbellekten siler. Bunların tümü script.mjs içinde gerçekleşir:

const restoreImageFromShare = async () => {
  const mediaCache = await getMediaCache();
  const image = await mediaCache.match('shared-image');
  if (image) {
    const blob = await image.blob();
    await drawBlob(blob);
    await mediaCache.delete('shared-image');
  }
};

Bu işlev daha sonra uygulama başlatıldığında kullanılır.

if (location.search.includes('share-target')) {
  restoreImageFromShare();
} else {
  drawDefaultImage();
}

6. 🐟 Resim İçe Aktarma Desteği Ekleme

Her şeyi sıfırdan çizmek zordur. Kullanıcılarınızın cihazlarından yerel bir resim yüklemesine olanak tanıyan bir özellik ekleyin.

Önce kanvas' drawImage() işlevini okuyun. Daha sonra <​input
type=file>
öğesi hakkında bilgi edinin.

Elinizdeki bu bilgiden yararlanarak import_image_legacy.mjs adlı dosyayı düzenleyebilir ve aşağıdaki snippet'i ekleyebilirsiniz. Dosyanın en üstünde, içe aktar düğmesini ve tuvale bir blob çizmenize olanak tanıyan drawBlob() işlevi içe aktarırsınız.

import { importButton, drawBlob } from './script.mjs';

const importImage = async () => {
  return new Promise((resolve) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'image/png, image/jpeg, image/*';
    input.addEventListener('change', () => {
      const file = input.files[0];
      input.remove();
      return resolve(file);
    });
    input.click();
  });
};

importButton.style.display = 'block';
importButton.addEventListener('click', async () => {
  const file = await importImage();
  if (file) {
    await drawBlob(file);
  }
});

7. 🐟 Dışa Aktarma Resim Desteği Ekleme

Kullanıcı, uygulamada oluşturulan bir dosyayı cihazına nasıl kaydedecek? Genellikle bu, bir <​a
download>
öğesiyle elde edilir.

İçeriği export_image_legacy.mjs dosyasına aşağıdaki gibi ekleyin. Dışa aktarma düğmesini ve kanvas içeriklerini bir blob'a dönüştüren toBlob() kolaylık işlevini içe aktarın.

import { exportButton, toBlob } from './script.mjs';

export const exportImage = async (blob) => {
  const a = document.createElement('a');
  a.download = 'fugu-greeting.png';
  a.href = URL.createObjectURL(blob);
  a.addEventListener('click', (e) => {
    a.remove();
    setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
  });
  setTimeout(() => a.click(), 0);
};

exportButton.style.display = 'block';
exportButton.addEventListener('click', async () => {
  exportImage(await toBlob());
});

8. 🐟 Dosya Sistemi Erişim API'sı Desteği ekleyin

Paylaşmak önemlidir ancak kullanıcılarınız en iyi çalışmalarını büyük olasılıkla kendi cihazlarına kaydetmek ister. Kullanıcılarınızın çizimlerini kaydetmesine (ve yeniden açmasına) olanak tanıyan bir özellik ekleyin.

Önceden, dosyaları içe aktarmak için <​input type=file> eski, dosyaları dışa aktarmak için ise <​a download> eski yaklaşımını kullanıyordunuz. Daha iyi bir deneyim için File System Access API'yi kullanacaksınız.

Bu API, işletim sisteminin dosya sisteminden dosya açılmasına ve dosyaların kaydedilmesine olanak verir. Aşağıdaki içeriği ekleyerek sırasıyla import_image.mjs ve export_image.mjs adlı iki dosyayı düzenleyin. Bu dosyaların yüklenmesi için script.mjs 🐡 emojilerini kaldırın.

Şu satırı değiştirin:

// Remove all the emojis for this feature test to succeed.
if ('show🐡Open🐡File🐡Picker' in window) {
  /* ... */
}

...bu satırla:

if ('showOpenFilePicker' in window) {
  /* ... */
}

import_image.mjs içinde:

import { importButton, drawBlob } from './script.mjs';

const importImage = async () => {
  try {
    const [handle] = await window.showOpenFilePicker({
      types: [
        {
          description: 'Image files',
          accept: {
            'image/*': ['.png', '.jpg', '.jpeg', '.avif', '.webp', '.svg'],
          },
        },
      ],
    });
    return await handle.getFile();
  } catch (err) {
    console.error(err.name, err.message);
  }
};

importButton.style.display = 'block';
importButton.addEventListener('click', async () => {
  const file = await importImage();
  if (file) {
    await drawBlob(file);
  }
});

export_image.mjs içinde:

import { exportButton, toBlob } from './script.mjs';

const exportImage = async () => {
  try {
    const handle = await window.showSaveFilePicker({
      suggestedName: 'fugu-greetings.png',
      types: [
        {
          description: 'Image file',
          accept: {
            'image/png': ['.png'],
          },
        },
      ],
    });
    const blob = await toBlob();
    const writable = await handle.createWritable();
    await writable.write(blob);
    await writable.close();
  } catch (err) {
    console.error(err.name, err.message);
  }
};

exportButton.style.display = 'block';
exportButton.addEventListener('click', async () => {
  await exportImage();
});

9. 🐟 Kişi Seçici API'sı Desteği Ekleyin

Kullanıcılarınız, tebrik kartlarına mesaj eklemek ve bir kullanıcıya kişisel olarak hitap etmek isteyebilir. Kullanıcılarınızın yerel kişilerinden birini (veya birkaçını) paylaşmalarını ve paylaşım mesajına adlarını eklemelerini sağlayan bir özellik ekleyin.

Android veya iOS cihazlarda Kişi Seçici API'si, cihazın kişi yöneticisi uygulamasından kişileri seçmenize ve uygulamaya geri döndürmenize olanak tanır. contacts.mjs dosyasını düzenleyin ve aşağıdaki kodu ekleyin.

import { contactsButton, ctx, canvas } from './script.mjs';

const getContacts = async () => {
  const properties = ['name'];
  const options = { multiple: true };
  try {
    return await navigator.contacts.select(properties, options);
  } catch (err) {
    console.error(err.name, err.message);
  }
};

contactsButton.style.display = 'block';
contactsButton.addEventListener('click', async () => {
  const contacts = await getContacts();
  if (contacts) {
    ctx.font = '1em Comic Sans MS';
    contacts.forEach((contact, index) => {
      ctx.fillText(contact.name.join(), 20, 16 * ++index, canvas.width);
    });
  }
});

10. 🐟 Eş Zamansız Pano API'sı Desteği

Kullanıcılarınız başka bir uygulamadaki uygulamayı uygulamanıza yapıştırmak veya uygulamanızdaki bir çizimi başka bir uygulamaya kopyalamak isteyebilir. Kullanıcılarınızın resimleri kopyalayıp uygulamanıza yapıştırmasına olanak tanıyan bir özellik ekleyin. Eşzamansız Pano Panosu sayesinde artık resim verilerini panoya okuyabilir ve yazabilirsiniz.

clipboard.mjs dosyasını bulun ve aşağıdakileri ekleyin:

import { copyButton, pasteButton, toBlob, drawImage } from './script.mjs';

const copy = async (blob) => {
  try {
    await navigator.clipboard.write([
      /* global ClipboardItem */
      new ClipboardItem({
        [blob.type]: blob,
      }),
    ]);
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const paste = async () => {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      try {
        for (const type of clipboardItem.types) {
          const blob = await clipboardItem.getType(type);
          return blob;
        }
      } catch (err) {
        console.error(err.name, err.message);
      }
    }
  } catch (err) {
    console.error(err.name, err.message);
  }
};

copyButton.style.display = 'block';
copyButton.addEventListener('click', async () => {
  await copy(await toBlob());
});

pasteButton.style.display = 'block';
pasteButton.addEventListener('click', async () => {
  const image = new Image();
  image.addEventListener('load', () => {
    drawImage(image);
  });
  image.src = URL.createObjectURL(await paste());
});

11. 🐟 Badging API Desteği

Kullanıcılarınız uygulamanızı yüklediğinde ana ekranlarında bir simge görüntülenir. Bu simgeyi, belirli bir çizimin aldığı fırça darbesi sayısı gibi eğlenceli bilgileri aktarmak için kullanabilirsiniz.

Kullanıcılarınız yeni bir fırça vuruşu yaptığında rozetin geri sayımını sağlayan bir özellik ekleyin. Badging API, uygulama simgesinde sayısal bir rozet ayarlamanızı sağlar. pointerdown etkinliği gerçekleştiğinde (yani fırça darbesi olduğunda) rozeti güncelleyebilir ve tuval temizlendiğinde rozeti sıfırlayabilirsiniz.

badge.mjs dosyasına aşağıdaki kodu girin:

import { canvas, clearButton } from './script.mjs';

let strokes = 0;

canvas.addEventListener('pointerdown', () => {
  navigator.setAppBadge(++strokes);
});

clearButton.addEventListener('click', () => {
  strokes = 0;
  navigator.setAppBadge(strokes);
});

12. 🐟 Ekran Uyandırma Kilidi API'sı Desteği Ekleyin

Bazen kullanıcılarınızın, bir çizime bakmak için ilham alacak kadar uzun bir süreye ihtiyacı olabilir. Ekranın uyanık kalmasını ve ekran koruyucunun devreye girmesini engelleyen bir özellik ekleyin. Screen Wake Lock API, kullanıcının ekranının uykuya geçmesini engeller. Sayfa Görünürlüğü ile tanımlanan görünürlük değişikliği etkinliği gerçekleştiğinde uyanık kalma kilidi otomatik olarak serbest bırakılır. Bu nedenle, sayfa tekrar görüntülendikten sonra uyanık kalma kilidine yeniden erişilmelidir.

wake_lock.mjs dosyasını bulup içeriği aşağıya ekleyin. Bunun çalışıp çalışmadığını test etmek için ekran koruyucunuzu bir dakika sonra gösterilecek şekilde yapılandırın.

import { wakeLockInput, wakeLockLabel } from './script.mjs';

let wakeLock = null;

const requestWakeLock = async () => {
  try {
    wakeLock = await navigator.wakeLock.request('screen');
    wakeLock.addEventListener('release', () => {
      console.log('Wake Lock was released');
    });
    console.log('Wake Lock is active');
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const handleVisibilityChange = () => {
  if (wakeLock !== null && document.visibilityState === 'visible') {
    requestWakeLock();
  }
};

document.addEventListener('visibilitychange', handleVisibilityChange);

wakeLockInput.style.display = 'block';
wakeLockLabel.style.display = 'block';
wakeLockInput.addEventListener('change', async () => {
  if (wakeLockInput.checked) {
    await requestWakeLock();
  } else {
    wakeLock.release();
  }
});

13. 🐟 Periyodik Arka Plan Senkronizasyonu API Desteği

Boş bir tuvalle başlamak sıkıcı olabilir. Kullanıcılarınızın tuvallerini her gün yeni bir resimle başlatmak için Düzenli Arka Plan Senkronizasyonu API'sini kullanabilirsiniz. Örneğin, Daima fugu fotoğrafı.

Bu işlem, Periyodik Arka Plan Senkronizasyonu'nu kaydeden bir dosya periodic_background_sync.mjs ve günün resmini indirmeyle ilgili bir başka dosya image_of_the_day.mjs gerektirir.

periodic_background_sync.mjs içinde:

import { periodicBackgroundSyncButton, drawBlob } from './script.mjs';

const getPermission = async () => {
  const status = await navigator.permissions.query({
    name: 'periodic-background-sync',
  });
  return status.state === 'granted';
};

const registerPeriodicBackgroundSync = async () => {
  const registration = await navigator.serviceWorker.ready;
  try {
    registration.periodicSync.register('image-of-the-day-sync', {
      // An interval of one day.
      minInterval: 24 * 60 * 60 * 1000,
    });
  } catch (err) {
    console.error(err.name, err.message);
  }
};

navigator.serviceWorker.addEventListener('message', async (event) => {
  const fakeURL = event.data.image;
  const mediaCache = await getMediaCache();
  const response = await mediaCache.match(fakeURL);
  drawBlob(await response.blob());
});

const getMediaCache = async () => {
  const keys = await caches.keys();
  return await caches.open(keys.filter((key) => key.startsWith('media'))[0]);
};

periodicBackgroundSyncButton.style.display = 'block';
periodicBackgroundSyncButton.addEventListener('click', async () => {
  if (await getPermission()) {
    await registerPeriodicBackgroundSync();
  }
  const mediaCache = await getMediaCache();
  let blob = await mediaCache.match('./assets/background.jpg');
  if (!blob) {
    blob = await mediaCache.match('./assets/fugu_greeting_card.jpg');
  }
  drawBlob(await blob.blob());
});

image_of_the_day.mjs içinde:

const getImageOfTheDay = async () => {
  try {
    const fishes = ['blowfish', 'pufferfish', 'fugu'];
    const fish = fishes[Math.floor(fishes.length * Math.random())];
    const response = await fetch(`https://source.unsplash.com/daily?${fish}`);
    if (!response.ok) {
      throw new Error('Response was', response.status, response.statusText);
    }
    return await response.blob();
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const getMediaCache = async () => {
  const keys = await caches.keys();
  return await caches.open(keys.filter((key) => key.startsWith('media'))[0]);
};

self.addEventListener('periodicsync', (syncEvent) => {
  if (syncEvent.tag === 'image-of-the-day-sync') {
    syncEvent.waitUntil(
      (async () => {
        try {
          const blob = await getImageOfTheDay();
          const mediaCache = await getMediaCache();
          const fakeURL = './assets/background.jpg';
          await mediaCache.put(fakeURL, new Response(blob));
          const clients = await self.clients.matchAll();
          clients.forEach((client) => {
            client.postMessage({
              image: fakeURL,
            });
          });
        } catch (err) {
          console.error(err.name, err.message);
        }
      })(),
    );
  }
});

14. 🐟 Şekil Algılama API'si Desteği ekleyin

Bazen kullanıcılarınızın çizimleri veya kullanılan arka plan resimleri barkodlar gibi yararlı bilgiler içerebilir. Shape Detection API ve özellikle Barcode Detection API, bu bilgileri ayıklamanıza olanak tanır. Kullanıcılarınızdan barkodları algılamaya çalışan bir özellik ekleyin. barcode.mjs dosyasını bulup içeriğini ekleyin. Bu özelliği test etmek için barkod içeren bir resmi tuvale yüklemeniz veya yapıştırmanız yeterlidir. QR kodları için görsel arama işleminden örnek bir barkodu kopyalayabilirsiniz.

/* global BarcodeDetector */
import {
  scanButton,
  clearButton,
  canvas,
  ctx,
  CANVAS_BACKGROUND,
  CANVAS_COLOR,
  floor,
} from './script.mjs';

const barcodeDetector = new BarcodeDetector();

const detectBarcodes = async (canvas) => {
  return await barcodeDetector.detect(canvas);
};

scanButton.style.display = 'block';
let seenBarcodes = [];
clearButton.addEventListener('click', () => {
  seenBarcodes = [];
});
scanButton.addEventListener('click', async () => {
  const barcodes = await detectBarcodes(canvas);
  if (barcodes.length) {
    barcodes.forEach((barcode) => {
      const rawValue = barcode.rawValue;
      if (seenBarcodes.includes(rawValue)) {
        return;
      }
      seenBarcodes.push(rawValue);
      ctx.font = '1em Comic Sans MS';
      ctx.textAlign = 'center';
      ctx.fillStyle = CANVAS_BACKGROUND;
      const boundingBox = barcode.boundingBox;
      const left = boundingBox.left;
      const top = boundingBox.top;
      const height = boundingBox.height;
      const oneThirdHeight = floor(height / 3);
      const width = boundingBox.width;
      ctx.fillRect(left, top + oneThirdHeight, width, oneThirdHeight);
      ctx.fillStyle = CANVAS_COLOR;
      ctx.fillText(
        rawValue,
        left + floor(width / 2),
        top + floor(height / 2),
        width,
      );
    });
  }
});

15. 🐡 Boşta Algılayıcı API Desteği Ekleme

Uygulamanızın kiosk benzeri bir ortamda çalıştığını düşünüyorsanız belirli bir süre etkinlik olmadığında tuvalin sıfırlanmasını sağlayabilirsiniz. Boşta Algılayıcı API'si, bir kullanıcının cihazı ile artık etkileşim kurmadığını algılamanızı sağlar.

idle_detection.mjs dosyasını bulup aşağıdaki içeriği yapıştırın.

import { ephemeralInput, ephemeralLabel, clearCanvas } from './script.mjs';

let controller;

ephemeralInput.style.display = 'block';
ephemeralLabel.style.display = 'block';

ephemeralInput.addEventListener('change', async () => {
  if (ephemeralInput.checked) {
    const state = await IdleDetector.requestPermission();
    if (state !== 'granted') {
      ephemeralInput.checked = false;
      return alert('Idle detection permission must be granted!');
    }
    try {
      controller = new AbortController();
      const idleDetector = new IdleDetector();
      idleDetector.addEventListener('change', (e) => {
        const { userState, screenState } = e.target;
        console.log(`idle change: ${userState}, ${screenState}`);
        if (userState === 'idle') {
          clearCanvas();
        }
      });
      idleDetector.start({
        threshold: 60000,
        signal: controller.signal,
      });
    } catch (err) {
      console.error(err.name, err.message);
    }
  } else {
    console.log('Idle detection stopped.');
    controller.abort();
  }
});

16. 🐡 Dosya İşleme API'sı Desteği Ekleme

Kullanıcılarınız bir resim dosyasını yeniden yerleştirebilse ve uygulamanız açılırsa ne olur? File Handling API bunu yapmanıza olanak tanır.

PWA'yı, resimler için bir dosya işleyici olarak kaydetmeniz gerekir. Bu işlem, Web Uygulaması Manifest dosyasında, manifest.webmanifest dosyasının altında bulunan alıntıdan gösterilmektedir. (Bu, manifest dosyasının zaten bir parçası olduğu için kendiniz eklemeniz gerekmez.)

{
  "file_handlers": [
    {
      "action": "./",
      "accept": {
        "image/*": [".jpg", ".jpeg", ".png", ".webp", ".svg"]
      }
    }
  ]
}

Açılan dosyaları gerçekten işlemek için aşağıdaki kodu file-handling.mjs dosyasına ekleyin:

import { drawBlob } from './script.mjs';

const handleLaunchFiles = () => {
  window.launchQueue.setConsumer((launchParams) => {
    if (!launchParams.files.length) {
      return;
    }
    launchParams.files.forEach(async (handle) => {
      const file = await handle.getFile();
      drawBlob(file);
    });
  });
};

handleLaunchFiles();

17. Tebrikler

🎉 Yaşadınız!

FuguProject projesi bağlamında geliştirilmekte olan çok fazla heyecan verici tarayıcı API'si var 🐡 bu codelab'de yüzeyler neredeyse hiç çizilmiyor.

Daha ayrıntılı bilgi edinmek veya yalnızca daha fazla bilgi edinmek için web.dev sitemizdeki yayınlarımızı takip edin.

web.dev sitesinin &ldabils&rdquo; bölümünün açılış sayfası.

Burada sona ermiyor. Henüz herkese açık olmayan güncellemeler için Fugu API izleyicimize erişebilir, gönderim yapılan veya kaynak denemesinde olan tüm çalışmalara, çalışmanın başladığı tüm tekliflere ve dikkate alınmayan ancak henüz başlatılmamış tüm tekliflere bağlantılar bulabilirsiniz.

Fugu API izleyicisi web sitesi

Bu codelab, Thomas Steiner (@tomayac) tarafından yazılmış olup sorularınızı yanıtlamaktan mutluluk duyacağım. Geri bildiriminizi sabırsızlıkla bekliyorum. Bu codelab'in şekillendirilmesine yardımcı olan Hemanth H.M (@GNUmanth), Christian Liebel (@christianliebel), Sven May (@Svenmay), Lars Knudsen (@larsgk) ve Jackie Han'a (@hanguokai) özellikle teşekkürler.