Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

React Native ile Endüstriyel Barkod Okuma: Ters Renk Data Matrix Kodları ve Zebra DataWedge Entegrasyonu

Giriş Modern lojistik ve depo yönetimi uygulamalarında barkod okuma, operasyonların omurgasını oluşturur. Ancak standart QR kod ve barkod okuma kütüphaneleri, endüstriyel ortamlarda karşılaşılan bazı özel durumlarda yetersiz kalabilir. Öz…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




Giriş



Modern lojistik ve depo yönetimi uygulamalarında barkod okuma, operasyonların omurgasını oluşturur. Ancak standart QR kod ve barkod okuma kütüphaneleri, endüstriyel ortamlarda karşılaşılan bazı özel durumlarda yetersiz kalabilir. Özellikle ters renk (inverted) Data Matrix kodları - beyaz zemin üzerine siyah yerine, siyah zemin üzerine beyaz kodlar - mobil kamera tabanlı okuyucular için ciddi bir zorluk teşkil eder.



Bu yazıda, React Native ile geliştirdiğimiz ve Zebra TC15 gibi endüstriyel el terminallerinde çalışan bir barkod okuma sistemi detaylandırılacaktır. Sistem, hem normal barkodları hem de ters renk Data Matrix kodlarını başarıyla okuyabilen hibrit bir yaklaşım sunmaktadır.






Proje Mimarisi



Projemiz üç ana katmandan oluşmaktadır:






1. React Native Katmanı





  • Vision Camera: Kamera erişimi ve frame processing


  • Dual Scanner System: Normal mod ve gelişmiş mod olmak üzere iki ayrı tarama sistemi


  • GS1 Parser: Barkod standardına uygun veri çıkarma






2. Native Android Katmanı





  • DataWedge Module (Kotlin): Zebra DataWedge SDK entegrasyonu


  • ML Kit Plugin (Java): Google ML Kit tabanlı barkod okuma


  • DPM Plugin (Java): Direct Part Marking için özel işlemler






3. Zebra DataWedge Entegrasyonu




  • Otomatik profil yapılandırması

  • RS507 Bluetooth scanner desteği

  • Ters renk (inverse) decode ayarları






Teknoloji Stack'i






{
"react-native": "0.78.0",
"react-native-vision-camera": "^4.7.3",
"@mgcrea/vision-camera-barcode-scanner": "^0.12.3",
"vision-camera-zxing": "^0.1.1",
"react-native-worklets-core": "^1.6.2",
"axios": "^1.13.2"
}






Native Dependencies:




  • Google ML Kit Barcode Scanning

  • ZXing (Zebra Crossing) Core

  • Zebra DataWedge SDK (cihazda yerleşik)






Problem: Ters Renk Data Matrix Kodları






Neden Özel Bir Çözüm Gerekti?



Standart barkod okuma kütüphaneleri (react-native-vision-camera, @mgcrea/vision-camera-barcode-scanner), normal Data Matrix kodlarını kolayca okurken, ters renk kodlarda başarısız oluyorlar. Bunun nedenleri:





  1. Kontrast Algılama: Çoğu barkod okuyucu, karanlık zemin üzerine açık kod yapısını beklemez


  2. Otomatik Eşik Değeri: Görüntü işleme algoritmaları, ters renk için optimize edilmemiştir


  3. DPM (Direct Part Marking): Endüstriyel parçalar üzerine lazer veya nokta vuruş ile işaretlenen kodlar, düşük kontrastlıdır






Gerçek Dünya Senaryosu



İlaç endüstrisinde, karton kutular üzerine basılan normal Data Matrix kodlarının yanı sıra, ilaç blisterlerinin üzerine lazer ile işaretlenmiş ters renk kodlar bulunmaktadır. Bu kodlar:




  • Siyah arka plan üzerine beyaz noktalardan oluşur

  • Çok küçük boyutludur (5x5mm civarı)

  • Düşük kontrastlıdır

  • Yansıma ve ışık problemlerine hassastır






Çözüm 1: Dual Scanner Sistemi



Projemizde iki ayrı tarama modu kullanıyoruz:






Normal Mod (Hızlı Tarama)



Normal barkodlar için optimize edilmiş kamera tabanlı tarama:




// Normal barkod tarayıcı - @mgcrea/vision-camera-barcode-scanner
const { props: normalScannerProps } = useBarcodeScanner({
fps: 5,
barcodeTypes: [
'data-matrix', // Öncelik 1
'qr',
'ean-13',
'ean-8',
'code-128',
'code-39',
'code-93',
'itf',
'upc-a',
'upc-e'
],
onBarcodeScanned: handleNormalBarcodeScanned,
});






Avantajları:




  • Hızlı ve düşük CPU kullanımı

  • Çoklu barkod formatı desteği

  • 5 FPS ile dengeli performans



Dezavantajları:




  • Ters renk kodları okuyamaz

  • DPM kodlarında zayıf performans






Gelişmiş Mod (Ters Renk + DPM)



Zorlu kodlar için özel işlenmiş frame processor:




const invertedFrameProcessor = useFrameProcessor((frame) => {
'worklet';
if (!isActive || !invertScan) return;

try {
let results = [];
let source = 'unknown';

// Öncelik 1: ML Kit Barcode Scanning
if (mlKitPlugin != null) {
const pluginResults = mlKitPlugin.call(frame, {});
if (pluginResults?.length > 0) {
source = 'ml-kit';
results = pluginResults;
}
}

// Öncelik 2: ZXing agresif ayarlar
if (results.length === 0) {
const zxingConfigs = [
{ tryHarder: true, tryInvert: false, formats: ['data-matrix'] },
{ tryHarder: true, tryInvert: true, formats: ['data-matrix'] },
{ tryHarder: true, tryInvert: true, tryRotate: true, formats: ['data-matrix'] },
];

for (const config of zxingConfigs) {
const zxingResults = zxing(frame, config);
if (zxingResults?.length > 0) {
source = 'zxing';
results = zxingResults;
break;
}
}
}

// Öncelik 3: Native DPM plugin
if (results.length === 0 && dpmPlugin != null) {
const pluginResults = dpmPlugin.call(frame, {});
if (pluginResults?.length > 0) {
source = 'native-dpm';
results = pluginResults;
}
}

// Sonuçları işle
results.forEach((res) => {
processInvertedBarcodeJS(res.value, res.bounds);
});

} catch (error) {
console.error('[Advanced Scanner] Error:', error);
}
}, [isActive, invertScan]);






Üç katmanlı fallback sistemi:





  1. ML Kit → En güvenilir, Google'ın AI tabanlı çözümü


  2. ZXing → Agresif ayarlarla (tryInvert, tryRotate)


  3. DPM Plugin → Özel preprocessing ile native çözüm






Çözüm 2: ML Kit ile Görüntü Ters Çevirme






MlKitDataMatrixPlugin.java



Native tarafta, görüntü işleme ile ters renk kodları normal hale getiriyoruz:




private List<Map<String, Object>> callback(Frame frame) {
List<Map<String, Object>> results = new ArrayList<>();

// 1. Normal görüntü ile dene
InputImage normalImage = InputImage.fromMediaImage(image, rotation);
List<Barcode> normalBarcodes = processImage(normalImage, "normal");

if (!normalBarcodes.isEmpty()) {
results.addAll(extractResults(normalBarcodes, "normal"));
} else {
// 2. Ters çevir ve tekrar dene
Bitmap bitmap = yuvToBitmap(yData, width, height);
Bitmap invertedBitmap = invertBitmap(bitmap);

InputImage invertedImage = InputImage.fromBitmap(invertedBitmap, rotation);
List<Barcode> invertedBarcodes = processImage(invertedImage, "inverted");

results.addAll(extractResults(invertedBarcodes, "inverted"));
}

return results;
}






Görüntü ters çevirme:




private Bitmap invertBitmap(Bitmap original) {
Bitmap inverted = Bitmap.createBitmap(
original.getWidth(),
original.getHeight(),
original.getConfig()
);

Canvas canvas = new Canvas(inverted);
Paint paint = new Paint();

// Renk matrisi: Her pikseli ters çevir
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
-1, 0, 0, 0, 255, // R -> 255 - R
0, -1, 0, 0, 255, // G -> 255 - G
0, 0, -1, 0, 255, // B -> 255 - B
0, 0, 0, 1, 0 // A -> A (değişmez)
});

paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(original, 0, 0, paint);

return inverted;
}






Bu yaklaşım sayesinde:




  • Beyaz zemin + siyah kod → Siyah zemin + beyaz kod

  • ML Kit bu formatta çok daha başarılı

  • %80+ okuma oranı elde ettik






Çözüm 3: Zebra DataWedge Entegrasyonu






DataWedge Nedir?



Zebra el terminallerinde (TC15, TC21, TC52, vb.) yerleşik gelen bir barkod okuma altyapısıdır. Özellikler:




  • Donanımsal barkod tarayıcı kontrolü

  • RS507 Bluetooth scanner desteği

  • Ters renk (inverse) decode yetenekleri


  • DPM modu (Direct Part Marking)

  • Intent ve Keystroke output






DWDemo Uygulaması Gereksiz!



Zebra cihazlarda, DataWedge profil yapılandırması için genellikle DWDemo adlı yardımcı uygulama kullanılır. Ancak bizim yaklaşımımız:



Otomatik profil oluşturma - DWDemo'ya gerek yok!




// DataWedgeModule.kt
private fun configureDataWedge(enableInverseMode: Boolean = true) {
val profileName = "MyAppProfile" // Uygulamanıza özel bir isim verin

// 1. Profil oluştur - EXPLICIT INTENT
val createIntent = Intent().apply {
action = DATAWEDGE_SEND_ACTION
setPackage("com.symbol.datawedge") // Sadece DataWedge alsın
putExtra("com.symbol.datawedge.api.CREATE_PROFILE", profileName)
}
reactApplicationContext.sendBroadcast(createIntent)

// 2. Profil yapılandırması
val profileConfig = Bundle().apply {
putString("PROFILE_NAME", profileName)
putString("PROFILE_ENABLED", "true")

// App Association
val appList = ArrayList<Bundle>()
val appConfig = Bundle().apply {
putString("PACKAGE_NAME", reactApplicationContext.packageName)
putStringArray("ACTIVITY_LIST", arrayOf("*"))
}
appList.add(appConfig)
putParcelableArrayList("APP_LIST", appList)

// Plugin yapılandırmaları
val pluginConfigs = ArrayList<Bundle>()

// Intent Output
pluginConfigs.add(createIntentPlugin())

// Keystroke Output
pluginConfigs.add(createKeystrokePlugin())

// Barcode Input - TERS RENK DESTEĞİ
pluginConfigs.add(createBarcodePlugin(enableInverseMode))

putParcelableArrayList("PLUGIN_CONFIG", pluginConfigs)
}

// Yapılandırmayı gönder
val configIntent = Intent().apply {
action = DATAWEDGE_SEND_ACTION
setPackage("com.symbol.datawedge")
putExtra("com.symbol.datawedge.api.SET_CONFIG", profileConfig)
}
reactApplicationContext.sendBroadcast(configIntent)
}









Ters Renk Data Matrix Ayarları



DataWedge'de ters renk decode için kritik ayarlar:




private fun createBarcodePlugin(enableInverse: Boolean): Bundle {
return Bundle().apply {
putString("PLUGIN_NAME", "BARCODE")

val barcodeProps = Bundle().apply {
putString("scanner_input_enabled", "true")

// DATA MATRIX TERS RENK
putString("decoder_datamatrix", "true")
// 0 = Normal, 1 = Inverse Only, 2 = Inverse Auto Detect
putString("decoder_datamatrix_inverse", if (enableInverse) "2" else "0")

// DPM (Direct Part Marking) modu - kritik!
putString("dpm_mode", if (enableInverse) "1" else "0")

// QR CODE TERS RENK
putString("decoder_qrcode", "true")
putString("decoder_qr_inverse", if (enableInverse) "2" else "0")

// GELİŞMİŞ AYARLAR
if (enableInverse) {
putString("inverse_1d_mode", "2") // Auto
putString("poor_quality_bcdecode_effort_level", "1")
}

// RS507 BLUETOOTH SCANNER
putString("scanner_selection", "auto")
putString("bt_scanner_enabled", "true")
putString("bt_reconnect", "true")
}

putBundle("PARAM_LIST", barcodeProps)
}
}






Kritik Parametreler:





  • decoder_datamatrix_inverse: "2" → Otomatik inverse detection


  • dpm_mode: "1" → Direct Part Marking aktif


  • poor_quality_bcdecode_effort_level: "1" → Daha agresif decode






Otomatik Başlatma (App.tsx)



Uygulama ilk açıldığında, DataWedge profili otomatik oluşturuluyor:




// App.tsx
useEffect(() => {
const initializeDataWedge = async () => {
if (Platform.OS !== 'android' || !NativeModules?.DataWedgeModule) {
return;
}

const dwInitialized = await AsyncStorage.getItem('dataWedgeInitialized');

if (!dwInitialized) {
console.log('[App Init] 🚀 FIRST LAUNCH - Initializing DataWedge');
console.log('[App Init] NO NEED FOR DWDemo - Full auto setup!');

await NativeModules.DataWedgeModule.enableDataWedge();
await NativeModules.DataWedgeModule.initializeDataWedge();

await AsyncStorage.setItem('dataWedgeInitialized', 'true');

console.log('[App Init] ✅ DataWedge profile created: MyAppProfile');
console.log('[App Init] 💡 DWDemo is NOT needed!');
}
};

setTimeout(initializeDataWedge, 2000);
}, []);






Sonuç:




  • Kullanıcı uygulamayı ilk açtığında profil otomatik oluşturuluyor

  • DWDemo'ya hiç ihtiyaç yok

  • Zebra cihazlarda %100 otomatik kurulum



Not: MyAppProfile yerine uygulamanıza uygun benzersiz bir profil adı kullanın. Package name'inizle eşleştirmek iyi bir pratiktir (örn: com.yourcompany.yourapp).






Çözüm 4: RS507 Bluetooth Scanner Entegrasyonu






RS507 Nedir?



Zebra RS507, el terminaline bluetooth ile bağlanan yüzük tipi tarayıcıdır:




  • Operatörlerin ellerini serbest bırakır

  • Tetik tuşu ile hızlı okuma

  • TC15 gibi cihazlarla sorunsuz çalışır






Otomatik Bağlanma



Gelişmiş mod açıldığında RS507 otomatik bağlanıyor:




// QrScannerModalNewErrorHand.js
useEffect(() => {
if (invertScan) {
if (Platform.OS === 'android' && NativeModules?.DataWedgeModule) {
console.log('[RS507] 🔗 Attempting to connect Bluetooth Scanner...');

NativeModules.DataWedgeModule.enableDataWedge()
.then(() => {
return NativeModules.DataWedgeModule.connectBluetoothScanner();
})
.then(() => {
console.log('[RS507] ✅ RS507 connection command sent');
console.log('[RS507] 📱 If paired, RS507 should connect automatically');
})
.catch((error) => {
console.log('[RS507] ⚠️ RS507 connection info:', error);
console.log('[RS507] 💡 Normal if not paired yet');
});
}
}
}, [invertScan]);









Keystroke Injection ile Otomatik İşleme



RS507 tetik tuşu ile okunan barkodlar, TextInput'a otomatik yazılıyor:




<TextInput
ref={barcodeInputRef}
style={styles.topBarcodeInput}
value={barcodeInput}
onChangeText={(text) => {
setBarcodeInput(text);

// Barkod geldiğinde otomatik işle
if (text.trim().length > 10) {
// Debounce timeout
if (processingTimeoutRef.current) {
clearTimeout(processingTimeoutRef.current);
}

processingTimeoutRef.current = setTimeout(() => {
const currentValue = text.trim();

// Duplicate check
if (currentValue && currentValue !== lastProcessedBarcodeRef.current) {
lastProcessedBarcodeRef.current = currentValue;
processBarcodeResultRef.current?.(currentValue);

// Input'u temizle
setBarcodeInput('');

// 500ms sonra yeni barkod için hazır
setTimeout(() => {
lastProcessedBarcodeRef.current = '';
barcodeInputRef.current?.focus();
}, 500);
}
}, 200); // 200ms debounce
}
}}
placeholder="Tetik tuşuna basın..."
showSoftInputOnFocus={false}
/>






Akış:




  1. RS507 tetik tuşuna basılır

  2. DataWedge barkodu okur

  3. Keystroke output → TextInput'a yazar


  4. onChangeText tetiklenir

  5. 200ms debounce sonrası otomatik işleme

  6. Input temizlenir, yeni barkod için hazır



Avantajlar:




  • Klavye görünmez (showSoftInputOnFocus={false})

  • Otomatik işleme - Enter'a gerek yok

  • Duplicate önleme mekanizması

  • Hızlı ardışık okuma






GS1 Standardı ve Barkod Parsing






GS1 Data Matrix Yapısı



İlaç ve lojistik sektöründe kullanılan Data Matrix kodları GS1 standardına uyar:




]d201234567890123421ABC12345678910LOTNO01117250131210630






AI (Application Identifier) Yapısı:





  • 01 → GTIN (Global Trade Item Number) - 14 digit


  • 21 → Serial Number - değişken uzunlukta


  • 17 → Expiry Date (YYMMDD) - 6 digit


  • 10 → Lot Number - değişken uzunlukta


  • 11 → Production Date (YYMMDD) - 6 digit



Group Separator: ASCII 29 (GS) karakteri değişken uzunluk AI'ları sonlandırır






Parser İmplementasyonu






const parseBarcode = (rawValue) => {
// Symbology prefix temizle (]C1, ]D1, vb.)
const normalized = cleanBarcodeValue(rawValue);
const value = normalized.toUpperCase();

if (!value.startsWith("01") || value.length < 16) {
throw new Error("Invalid QR Code format (GTIN missing)");
}

const parsed = {
"01": value.substring(2, 16), // GTIN
};

let cursor = 16;
while (cursor < value.length - 1) {
cursor = skipGroupSeparators(value, cursor);
if (cursor >= value.length - 1) break;

const ai = value.substring(cursor, cursor + 2);
if (!GS1_KNOWN_AIS.includes(ai)) break;

cursor += 2;
cursor = skipGroupSeparators(value, cursor);

// Fixed length AI
if (GS1_FIXED_LENGTH_AIS[ai]) {
const len = GS1_FIXED_LENGTH_AIS[ai];
parsed[ai] = value.substring(cursor, cursor + len);
cursor += len;
continue;
}

// Variable length AI
const maxLen = GS1_VARIABLE_LENGTH_AIS[ai] || 30;
const { field, nextIndex } = extractVariableField(value, cursor, maxLen);
parsed[ai] = field;
cursor = nextIndex;
}

// GTIN'den sıfırları temizle (EAN-11)
const ean11 = parsed["01"].replace(/^0+/, "");

return {
Ean11: ean11,
Sernr: parsed["21"] || parsed["10"], // Serial
Vfdat: normalizeGs1Date(parsed["17"]), // Expiry
Lotnr: parsed["10"] || parsed["21"], // Lot
Mfdat: normalizeGs1Date(parsed["11"]), // Production
};
};









Group Separator Yönetimi



Değişken uzunluklu AI'lar GS (ASCII 29) ile sonlandırılır:




const GS1_GROUP_SEPARATOR = String.fromCharCode(29);

const skipGroupSeparators = (value, startIndex = 0) => {
let cursor = startIndex;
while (cursor < value.length && value[cursor] === GS1_GROUP_SEPARATOR) {
cursor += 1;
}
return cursor;
};

const extractVariableField = (value, start, maxLength = 30) => {
let cursor = skipGroupSeparators(value, start);
let end = Math.min(value.length, cursor + maxLength);

// GS bulursa orada sonlandır
const gsIndex = value.indexOf(GS1_GROUP_SEPARATOR, cursor);
if (gsIndex !== -1 && gsIndex < end) {
end = gsIndex;
}

// Fixed AI bulursa orada sonlandır
const fixedIndex = findNextFixedAiIndex(value, cursor);
if (fixedIndex !== -1 && fixedIndex < end) {
end = fixedIndex;
}

const field = value.substring(cursor, end);
let nextIndex = end;

if (gsIndex !== -1 && gsIndex === end) {
nextIndex = gsIndex + 1; // GS'i atla
}

return { field, nextIndex };
};









Backend API Entegrasyonu



Okunan barkodlar, modern RESTful API üzerinden backend sistemine gönderilir. Bu sayede:




  • Merkezi veri yönetimi sağlanır

  • Gerçek zamanlı stok takibi yapılır

  • Audit trail (denetim izi) oluşturulur

  • Çoklu cihaz senkronizasyonu mümkün olur






Frontend Entegrasyon Kodu



Okunan barkodlar parse edildikten sonra batch olarak API'ye gönderilir:




const sendBarcodesToAPI = async (barcodes, gtin) => {
// Personel bilgisini AsyncStorage'dan al
const employeeId = await AsyncStorage.getItem('employeeId');

// Barkodları parse et
const items = barcodes.map(barcode => {
const parsed = parseBarcode(barcode);
return {
gtin: parsed.Ean11,
serialNumber: parsed.Sernr,
expiryDate: parsed.Vfdat,
lotNumber: parsed.Lotnr,
productionDate: parsed.Mfdat
};
});

// REST API request payload
const payload = {
employeeId: employeeId,
gtin: gtin,
scannedAt: new Date().toISOString(),
items: items,
deviceInfo: {
platform: Platform.OS,
version: Platform.Version
}
};

try {
const response = await axios.post(
`${API_BASE_URL}/api/barcodes/batch`,
payload,
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_TOKEN}`,
'X-Device-Id': await AsyncStorage.getItem('deviceId'),
},
timeout: 30000, // 30 saniye timeout
}
);

// Backend'den başarılı yanıt kontrolü
if (response.status === 200 || response.status === 201) {
if (response.data.success) {
return {
success: true,
message: response.data.message,
transactionId: response.data.transactionId
};
}
}

throw new Error(response.data.message || 'Unknown error');
} catch (error) {
// Hata detaylarını logla
console.error('[API] Error sending barcodes:', error);

if (error.response) {
// Backend'den hata yanıtı geldi
throw new Error(
error.response.data.message ||
`Server error: ${error.response.status}`
);
} else if (error.request) {
// Request gönderildi ama yanıt gelmedi
throw new Error('No response from server. Check your connection.');
} else {
// Request oluşturulurken hata
throw new Error(error.message);
}
}
};









Backend API Endpoint Örneği



Backend tarafında beklenen endpoint yapısı (Node.js/Express örneği):




// POST /api/barcodes/batch
app.post('/api/barcodes/batch', authenticate, async (req, res) => {
try {
const { employeeId, gtin, items, scannedAt, deviceInfo } = req.body;

// Validasyon
if (!employeeId || !gtin || !items || items.length === 0) {
return res.status(400).json({
success: false,
message: 'Missing required fields'
});
}

// Tüm barkodların aynı GTIN'e sahip olduğunu kontrol et
const allSameGtin = items.every(item => item.gtin === gtin);
if (!allSameGtin) {
return res.status(400).json({
success: false,
message: 'All barcodes must have the same GTIN'
});
}

// Database'e kaydet
const transaction = await db.transaction(async (trx) => {
const batchId = await trx('barcode_batches').insert({
employee_id: employeeId,
gtin: gtin,
scanned_at: scannedAt,
device_platform: deviceInfo.platform,
item_count: items.length
}).returning('id');

// Her bir barkodu kaydet
const barcodeRecords = items.map(item => ({
batch_id: batchId[0],
gtin: item.gtin,
serial_number: item.serialNumber,
expiry_date: item.expiryDate,
lot_number: item.lotNumber,
production_date: item.productionDate
}));

await trx('barcodes').insert(barcodeRecords);

return batchId[0];
});

res.status(201).json({
success: true,
message: `Successfully saved ${items.length} barcodes`,
transactionId: transaction
});

} catch (error) {
console.error('Batch save error:', error);
res.status(500).json({
success: false,
message: 'Failed to save barcodes'
});
}
});









API Response Formatı



Başarılı Yanıt:




{
"success": true,
"message": "Successfully saved 25 barcodes",
"transactionId": "TXN-2025-12-19-001234"
}






Hata Yanıtı:




{
"success": false,
"message": "All barcodes must have the same GTIN",
"errorCode": "INVALID_GTIN_MISMATCH"
}









Güvenlik Notları



Backend API entegrasyonunda dikkat edilmesi gerekenler:





  1. Authentication & Authorization




    • JWT token kullanımı (Bearer token)

    • Token'ların güvenli saklanması (Keychain/KeyStore)

    • Token refresh mekanizması




  2. API Key Management




    • Hardcoded API key'ler kullanmayın

    • Environment variables veya secure storage

    • Cihaz bazlı unique identifier (device ID)




  3. HTTPS Zorunluluğu




    • TLS 1.2+ kullanın

    • Certificate pinning düşünün

    • Man-in-the-middle saldırılarına karşı koruma




  4. Rate Limiting




    • Backend'de rate limiting uygulayın

    • Mobil uygulamada retry logic ekleyin

    • Exponential backoff stratejisi




  5. Data Validation




    • Backend'de tüm input'ları validate edin

    • GTIN formatı doğrulama

    • Tarih formatı kontrolleri (expiry date, production date)






// Token güvenli saklama örneği
import * as SecureStore from 'expo-secure-store';

const saveAuthToken = async (token) => {
await SecureStore.setItemAsync('api_token', token);
};

const getAuthToken = async () => {
return await SecureStore.getItemAsync('api_token');
};









Kullanıcı Deneyimi Optimizasyonları






1. Dual Mode Switch



Kullanıcı, tarama modunu anında değiştirebilir:




const saveScannerModeSetting = async (value) => {
await AsyncStorage.setItem('invertScan', JSON.stringify(value));
setInvertScan(value);

// DataWedge'e inverse mode değişikliğini bildir
if (Platform.OS === 'android' && NativeModules?.DataWedgeModule) {
await NativeModules.DataWedgeModule.setInverseMode(value);
}

// Tarama durumunu sıfırla
setScannedCount(0);
scannedBarcodesRef.current = new Set();
};






Switch Component:




<Switch
trackColor={{ false: "#767577", true: "#f9aa33" }}
thumbColor={invertScan ? "#ffc107" : "#f4f3f4"}
onValueChange={saveScannerModeSetting}
value={invertScan}
/>









2. Görsel Geri Bildirim



Barkod okununca merkezi vurgu kutusu:




if (!scannedBarcodesRef.current.has(normalizedBarcodeValue)) {
scannedBarcodesRef.current.add(normalizedBarcodeValue);
setScannedCount((prevCount) => prevCount + 1);

// Yeşil vurgu - yeni barkod
highlightRef.current = { bounds: finalBounds, color: 'green' };
} else {
// Kırmızı vurgu - duplicate
highlightRef.current = { bounds: finalBounds, color: 'red' };
}

setTimeout(() => {
highlightRef.current = null;
}, 500);









3. Otomatik Gönderim



Hedef adet girilirse, otomatik backend API'ye gönderim:




useEffect(() => {
if (autoSend &&
targetCount &&
parseInt(targetCount) === scannedCount &&
scannedCount > 0 &&
!autoSendTriggered) {
setAutoSendTriggered(true);
setIsActive(false);
setTimeout(() => {
handleSendBarcodes();
}, 500);
}
}, [targetCount, scannedCount, autoSend]);









4. Gelişmiş Mod Rehber Kutusu



Gelişmiş modda, kullanıcıya sürekli görsel rehber:




{invertScan && (
<View style={styles.scanGuideBox}>
{/* Kesik çizgili gri çerçeve */}
<View style={styles.scanGuideLineTop} />
<View style={styles.scanGuideLineBottom} />
<View style={styles.scanGuideLineLeft} />
<View style={styles.scanGuideLineRight} />

{/* Köşe işaretleri */}
<View style={[styles.scanGuideCorner, styles.scanGuideCornerTopLeft]} />
<View style={[styles.scanGuideCorner, styles.scanGuideCornerTopRight]} />
<View style={[styles.scanGuideCorner, styles.scanGuideCornerBottomLeft]} />
<View style={[styles.scanGuideCorner, styles.scanGuideCornerBottomRight]} />
</View>
)}









Performans İyileştirmeleri






1. Frame Processor FPS Optimizasyonu






// Normal mod - 5 FPS (yeterli hız)
<Camera
frameProcessorFps={5}
preset="high"
{...normalScannerProps}
/>

// Gelişmiş mod - 2 FPS (CPU tasarrufu, kaliteli işleme)
<Camera
frameProcessor={invertedFrameProcessor}
frameProcessorFps={2}
preset="max"
videoStabilizationMode="cinematic-extended"
/>






Neden düşük FPS?




  • Data Matrix decode CPU intensive

  • 2 FPS bile saniyede 2 okuma fırsatı

  • Gerçek dünya testlerinde yeterli






2. Yüksek Çözünürlük Formatı






const highResFormat = useCameraFormat(device, [
{ videoResolution: { width: 1920, height: 1080 } },
{ videoResolution: { width: 1280, height: 720 } },
]);






Neden yüksek çözünürlük?




  • Küçük Data Matrix kodları için detay kritik

  • ML Kit ve ZXing daha başarılı

  • 1080p ideal, 720p minimum






3. Worklets ile JS Bridge Optimizasyonu



Frame processor'dan JS'e veri aktarımı:




const processInvertedBarcodeJS = Worklets.createRunOnJS((barcodeValue, bounds) => {
processBarcodeResult(barcodeValue, bounds);
});

// Worklet içinde
if (barcodeDetected) {
processInvertedBarcodeJS(value, bounds);
}






Avantaj: UI thread bloklanmaz






Hata Yönetimi ve Logging






Detaylı Log Sistemi






const logError = async (error, context, additionalData = {}) => {
const errorLog = {
timestamp: new Date().toISOString(),
error: {
message: error.message,
stack: error.stack,
name: error.name
},
context: context,
additionalData: additionalData,
deviceInfo: {
platform: Platform.OS,
version: Platform.Version
}
};

console.error(`[QR Scanner Error - ${context}]:`, errorLog);

// AsyncStorage'a kaydet
const existingLogs = await AsyncStorage.getItem('crashLogs');
const logs = existingLogs ? JSON.parse(existingLogs) : [];
logs.unshift(errorLog);

// Son 50 hatayı sakla
const limitedLogs = logs.slice(0, 50);
await AsyncStorage.setItem('crashLogs', JSON.stringify(limitedLogs));
};









Native Tarafta Detaylı Loglar






android.util.Log.d("DataWedge", "═══════════════════════════════════════")
android.util.Log.d("DataWedge", "📡 BROADCAST RECEIVED")
android.util.Log.d("DataWedge", "Data String: $data")
android.util.Log.d("DataWedge", "Label Type: $type")
android.util.Log.d("DataWedge", "═══════════════════════════════════════")






Emoji kullanımı ile log filtreleme kolaylaşır:





  • 📡 → DataWedge broadcast


  • ✅ → Başarılı işlem


  • ❌ → Hata


  • ⚠️ → Uyarı


  • 🔄 → Mod değişikliği






Test ve Sonuçlar






Gerçek Dünya Test Senaryosu



Ortam: İlaç deposu, karışık aydınlatma



Test Edilen Barkodlar:




  1. Normal Data Matrix (karton kutu üzerinde)

  2. Ters renk Data Matrix (blister üzerinde)

  3. DPM lazer işaretli (düşük kontrast)

  4. QR kod (karma)






Sonuçlar




































Mod Normal DM Ters Renk DM DPM QR
Normal Mod 95% 10% 5% 98%
Gelişmiş Mod (Kamera) 90% 75% 60% 95%
Gelişmiş Mod (RS507) 98% 85% 80% 99%


Önemli Bulgular:




  • ML Kit ters renk için en başarılı

  • RS507 ile DPM okuma %80+

  • Dual system ile tüm senaryolar kapsandı






Performans Metrikleri






Normal Mod:
- CPU: %15-20
- Pil tüketimi: Düşük
- Ortalama okuma süresi: 0.5s

Gelişmiş Mod (Kamera):
- CPU: %35-45
- Pil tüketimi: Orta
- Ortalama okuma süresi: 1.5s

Gelişmiş Mod (RS507):
- CPU: %10-15 (native)
- Pil tüketimi: Düşük
- Ortalama okuma süresi: 0.3s









Sorun Giderme






1. RS507 Bağlanmıyor



Çözüm:




# Zebra cihazda Bluetooth ayarları
Settings → Bluetooth → Scan for devices
# RS507'yi bul ve pair et
# Uygulama otomatik bağlanacak









2. DataWedge Profili Oluşmuyor



Log kontrolü:




adb logcat | grep DataWedge






Sorun: Explicit intent kullanılmamış



Çözüm:




// YANLIŞ
val intent = Intent("com.symbol.datawedge.api.ACTION")

// DOĞRU
val intent = Intent().apply {
action = "com.symbol.datawedge.api.ACTION"
setPackage("com.symbol.datawedge") // Kritik!
}









3. Ters Renk Kodlar Hala Okunmuyor



Kontrol listesi:




  • [ ] decoder_datamatrix_inverse: "2" ayarlandı mı?

  • [ ] dpm_mode: "1" aktif mi?

  • [ ] Kamera formatı yüksek çözünürlükte mi? (min 720p)

  • [ ] Işık yeterli mi? (çok parlak veya karanlık olmamalı)

  • [ ] Kod zarar görmemiş mi?






4. ML Kit Plugin Çalışmıyor



Frame reference hatasını çözmek:




// Lifecycle management
frame.incrementRefCount(); // Frame'i uzat
try {
// İşlemler
Image image = frame.getImage();
// ...

image.close(); // Önemli: close et
} finally {
// frame.decrementRefCount() - Otomatik (VisionCamera 4.x)
}









Sonuç ve Öneriler



Bu projede React Native ile endüstriyel seviye bir barkod okuma sistemi geliştirdik. Başlıca özellikler:






✅ Başarılar





  1. Hibrit Yaklaşım: Kamera + DataWedge + RS507


  2. Ters Renk Desteği: ML Kit ile görüntü ters çevirme


  3. Otomatik Yapılandırma: DWDemo'ya gerek yok


  4. GS1 Uyumlu: Standart compliant parsing


  5. RESTful API: Modern backend entegrasyonu


  6. Kullanıcı Dostu: Dual mode, görsel feedback






📚 Öğrenilenler





  1. DataWedge Intent Yapısı: Explicit intent kritik


  2. Frame Processor Lifecycle: Ref count management


  3. Bitmap İşleme: ColorMatrix ile inversion


  4. Worklets: JS bridge optimization


  5. GS1 Parsing: Group separator management


  6. REST API Design: Batch processing ve error handling






🚀 Gelecek İyileştirmeler





  1. OCR Entegrasyonu: Baskı hataları için fallback


  2. Offline-First Mimari: SQLite cache + background sync queue


  3. Real-time Validation: Backend'den anlık GTIN doğrulama


  4. AI Preprocessing: Görüntü kalitesi iyileştirme (sharpening, denoising)


  5. Multi-Device Support: Honeywell, Datalogic, SOTI vb.


  6. Analytics Dashboard: Okuma başarı oranları ve performans metrikleri






💡 Öneriler



Zebra cihaz kullananlar için:




  • DataWedge SDK'yı ihmal etmeyin

  • Profile auto-configuration yazın

  • RS507 entegrasyonu kullanıcı deneyimini çok iyileştirir



Ters renk kod okumak isteyenler için:




  • ML Kit'e öncelik verin

  • Bitmap inversion stratejisi çalışıyor

  • Yüksek çözünürlük kritik (min 720p)



React Native geliştiriciler için:




  • Frame processor'lar güçlü ama dikkatli kullanın

  • Worklets ile JS bridge optimize edin

  • Native module yazmaktan korkmayın



Backend entegrasyonu için:




  • Batch processing endpoint'leri kullanın (tek tek gönderim yerine)

  • Transaction ID ile işlem takibi yapın

  • Offline-first yaklaşım düşünün (SQLite + sync)

  • Proper error handling ve retry mekanizmaları ekleyin






Kaynaklar ve Linkler






Resmi Dokümantasyon








Açık Kaynak Kütüphaneler








Topluluk








Yazar Notu: Bu proje, gerçek dünya lojistik operasyonlarında kullanılmakta ve günde ortalama 5000+ barkod okuma yapılmaktadır. Herhangi bir sorunuz veya geri bildiriminiz varsa, yorumlarda paylaşabilirsiniz.



GitHub: [Projeyi yıldızlamayı unutmayın! ⭐]



Etiketler: #ReactNative #DataWedge #Zebra #BarcodeScanning #DataMatrix #MLKit #ZXing #MobileDevelopment #EnterpriseApps #GS1 #RESTful #BackendAPI






Son güncelleme: Aralık 2025

2. Cyber Threat Intelligence & Forensik

CTI Threat Relationship Graph4 Knoten / 3 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten React Native ile Endüstriyel Barkod Okuma: Ters Renk Data Matrix Kodları ve Zebra DataWedge Entegrasyonu

Thematisch verwandte Begriffe: React, Native, Endüstriyel, Barkod · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-101041 | The account recovery (password reset) functionality in the vulnerabilit…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag