# WebView Köprüsü

Uygulama içi checkout takibi
Kaynak: https://selwise.com/docs/mobile/webview-bridge

Çoğu mobil uygulamada ödeme akışı native ekran değil bir WebView'dir. Mağaza sitesi uygulama içinde çalıştığını fark edip analitiğini sayfadan **uzağa** yönlendirir: Akinon `chakra_zero` vitrini olayı `window.ReactNativeWebView.postMessage(...)` ile iletir ve `window.dataLayer`'a hiç yazmaz. Sayfadaki hiçbir dinleyici, Selwise dahil, bir şey göremez; sonuç: kullanıcı uygulamada ürün gezer, WebView'de satın alır ve sipariş hiçbir mobil temasa bağlanmaz. Köprü bu mesajları native taraftan toplayıp SDK'ya aktarır; uygulama içi gezinme ile WebView'deki satın alma **tek yolculuk** olur.

## Kurulum

```tsx
import { WebView } from 'react-native-webview';
import { WebViewBridge, WEBVIEW_BRIDGE_SCRIPT } from '@selwise/react-native';

const bridge = useMemo(
  () =>
    new WebViewBridge(selwise, {
      debug: __DEV__,
      onUnhandled: (event, payload) => console.log('eşlenmeyen olay', event, payload),
    }),
  []
);

selwise.setScreen('app://checkout');   // WebView açılmadan önce

<WebView
  source={{ uri: checkoutUrl }}
  injectedJavaScriptBeforeContentLoaded={WEBVIEW_BRIDGE_SCRIPT}
  onMessage={(e) => bridge.handleMessage(e.nativeEvent.data)}
/>
```

```ts
new WebViewBridge(selwise: Selwise, options?: {
  onUnhandled?: (event: string, payload: unknown) => void;   // eşlenemeyen mesajlar
  debug?: boolean;
})
bridge.handleMessage(raw: unknown): boolean   // olay üretildiyse true
```

`handleMessage`, React Native'in verdiği JSON metnini ya da ayrıştırılmış nesneyi kabul eder. Mesajlar bir web sayfasından gelen **güvensiz girdidir**: her alan doğrulanır, tanınmayan mesaj iletilmez. `setScreen`'i WebView'den önce çağırmak, içeriden gelen olayların `app://checkout` gibi kararlı bir ekranla işlenmesini sağlar; köprü ekranı kendisi değiştirmez.

`WEBVIEW_BRIDGE_SCRIPT` iki iş yapar:

1. `window.isMobileApp = true` yazar; vitrinler bunu uygulama içi WebView'de olduklarını anlamak için okur ve olayları köprüye yönlendirmeyi bununla başlatır.
2. `window.dataLayer.push` çağrılarını `postMessage`'a da yansıtır; yönlendirmeyi hiç uygulamamış projeler de aynı dinleyiciyle kapsanır.

Zaten yönlendiren bir sayfada da enjekte edilebilir: köprü siparişleri sipariş koduna göre tekilleştirir.

## Hangi olaylar taşınır

Köprü hem GA4 biçimini (`ecommerce.items[]`) hem UA Enhanced Ecommerce biçimini (`ecommerce.<eylem>.products[]`) okur.

| Vitrin olayı | Selwise olayı |
|---|---|
| `page_view` | `page_view` |
| `view_item` | `product_view` |
| `view_item_list` | `product_impression` |
| `select_item` | `product_click` |
| `add_to_cart`, `addToCart`, `sepete_ekle` | `add_to_cart` |
| `remove_from_cart` | `remove_from_cart` |
| `view_cart`, `sepet_goruntule` | `cart_view` |
| `begin_checkout`, `odemeye_basla` | `checkout_begin` |
| `add_shipping_info`, `add_payment_info` | `checkout_progress` |
| `add_to_wishlist` | `wishlist` |
| `login`, `sign_up` | `user_login`, `user_signup` |
| `search` | `search_query` |
| `purchase`, `siparis_ver` | Sipariş (`trackOrder`); aşağıda |

Olayın üstverisine `source: webview`, `webviewEvent` (özgün ad), varsa `currency`, `value` ve `itemCount` yazılır. İlk ürünün kodu `entityId` ve `productItemCode` olur. Ürün kodu sırayla `item_id`, `id`, `sku`, `item_code` alanlarından okunur; `item_id` önce gelir çünkü ürün düzeyindeki raporlar besleme `item_code`'una bununla eşleşir.

> **eeEvent bilerek eşlenmez**
>
> Bazı standart GTM bağdaştırıcıları ürün detayı, ürün tıklaması ve ürün gösterimini aynı `eeEvent` adıyla gönderir; ad tek başına hangisinin kastedildiğini söylemez ve eşlemek tıklamaları görüntüleme diye yazardı. Bu projeler için `olay + ecommerce eylemi` bileşik eşlemesine ihtiyaç vardır; `onUnhandled` bunları size gösterir.

## Sipariş

`purchase` mesajı `trackOrder` çağrısına dönüştürülür: `orderId` sipariş koduyla, `total` `ecommerce.value` ile (yoksa `0`), `currency` yalnızca sayfa gönderdiyse, kalemler `productItemCode`, `name`, `quantity`, `unitPrice` ile; üstveri `source: webview`. Sipariş kodu sırayla `ecommerce.transaction_id`, `transactionId`, `purchase.actionField.id`, mesajın `transaction_id` ve `orderId` alanlarından okunur.

- **Sipariş kodu yoksa mesaj düşer** (`onUnhandled` çağrılır). Kodsuz sipariş tekilleştirilemez ve teşekkür sayfasını yenilemek ikinci bir sipariş yaratırdı.
- Köprü, oturum boyunca gördüğü kodları hatırlar ve aynı kodu ikinci kez iletmez; bu hatırlama bellektedir. Asıl koruma sunucudadır: `orderId` tekilleştirme anahtarıdır, aynı kodla tekrar gönderilen sipariş ikiye katlanmaz.
- Gönderim başarısız olursa kod unutulur ve sonraki mesajda yeniden denenir.
- `value` gelmezse sipariş `0` toplamla yazılır. Vitrinin `value` göndermediğinden şüpheleniyorsanız siparişi kendi sisteminizden de aynı `orderId` ile bildirin.

> **Sipariş kodunu tutarlı gönderin**
>
> Siparişi hem WebView'den hem kendi kodunuzdan (`trackOrder`) bildirirseniz iki yolda **aynı** sipariş kodunu kullanın. Farklıysa tekilleştirme çalışmaz ve ciro iki katı görünür. Ayrıntı: [Event Takibi](/docs/mobile/tracking#sipariş).

WebView içindeki sayfada vitrinin kendi Selwise script'i de çalışıyorsa aynı olaylar iki yoldan gelebilir; ölçümü tek yoldan yapın ve köprüyü yalnızca script'in çalışmadığı WebView'ler için kullanın.

## Doğrulama

1. Uygulamada bir ürün gezin, WebView ödemeye girin ve test siparişini tamamlayın.
2. `debug: true` ile Metro konsolunda `[Selwise/WebView] Forwarded ... order` satırını görün.
3. Panelde **Analitik → Müşteri Yolları** (Analytics → Customer Paths) ekranında yolculuğun kesintisiz göründüğünü ve **Conversion Sources** ekranında siparişin bir mobil temasa atfedildiğini kontrol edin.

Yolculuk WebView'e girişte kopuyorsa köprü bağlanmamıştır (`injectedJavaScriptBeforeContentLoaded` verilmemiş ya da `onMessage` bağlı değil). Hiçbir şey gelmiyorsa [Sorun Giderme](/docs/mobile/troubleshooting).

## Sırada ne var

- [Akinon App Maker Eklentisi](/docs/mobile/app-maker): `Selwise.webViewBridge()` hazır köprüyü verir
- [Sorun Giderme](/docs/mobile/troubleshooting)
