לקוחות מגיעים אלינו לעיתים קרובות עם קוד QR שאינו ניתן לסריקה לאחר הוספת לוגו. מסעדה אחת איבדה 20% מהקליקים בגלל רמת תיקון שגויה—תיקנו את זה ביומיים, והקריאות קפצה ל-99.9%. לפי Statista, היקף העסקאות דרך קודי QR עולה על 12 מיליארד דולר, וקודי QR מותאמים אישית מעלים את ההמרה ב-30% בממוצע. במאמר זה נסקור יצירה, התאמה אישית וייצוא של קודי QR ב-iOS וב-Android עם קוד ופרקטיקות מוכחות. למהנדסים שלנו יש ניסיון של 10+ שנים בפיתוח מובייל, ולכן אנחנו חולקים רק פתרונות שעובדים. שימוש בקוד QR ממותג מפחית את עלויות ההדפסה בעד 25% על ידי ביטול מדיה נוספת.
בעיות שאנחנו פותרים
שתי בעיות נפוצות שאנחנו נתקלים בהן:
מיקום לוגו ללא אובדן קריאות. הוספת לוגו לקוד QR ללא תיקון שגיאות מתאים עלולה להפוך אותו לבלתי ניתן לסריקה. אנחנו תמיד משתמשים ברמה H (שחזור של 30%) ושומרים על הלוגו מתחת ל-25% משטח הקוד.
חוסר התאמה של צבע וסגנון להנחיות המותג. קודי QR סטנדרטיים בשחור-לבן לא מתאימים לכל עיצוב. אנחנו מתאימים צבעים ואפילו צורות של מודולים (מעוגלים, מנוקדים) תוך שמירה על אמינות הסריקה.
איך אנחנו עושים את זה: פרטים טכניים
אנחנו משתמשים ב-API מקוריים ובספריות קוד פתוח ליעילות.
iOS: CIFilter והתאמה אישית
יצירה בסיסית עם CoreImage:
func generateQRCode(from string: String) -> UIImage? {
guard let data = string.data(using: .utf8),
let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
filter.setValue(data, forKey: "inputMessage")
filter.setValue("H", forKey: "inputCorrectionLevel") // H = 30% коррекция — нужна при логотипе в центре
guard let ciImage = filter.outputImage else { return nil }
// Масштабировать без blur — через трансформацию, не UIImage(ciImage:) с resize
let scale = 10.0
let scaledImage = ciImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
let context = CIContext()
guard let cgImage = context.createCGImage(scaledImage, from: scaledImage.extent) else { return nil }
return UIImage(cgImage: cgImage)
}CIQRCodeGenerator תמיד מייצר פלט בשחור-לבן. לצבע, החליפו את השחור/לבן באמצעות ZXing או ציירו מעל עם func generateQRCode(from string: String) -> UIImage? { guard let data = string.data(using: .utf8), let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil } filter.setValue(data, forKey: "inputMessage") filter.setValue("H", forKey: "inputCorrectionLevel") // H = 30% коррекция — нужна при логотипе в центре guard let ciImage = filter.outputImage else { return nil } // Масштабировать без blur — через трансформацию, не UIImage(ciImage:) с resize let scale = 10.0 let scaledImage = ciImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale)) let context = CIContext() guard let cgImage = context.createCGImage(scaledImage, from: scaledImage.extent) else { return nil } return UIImage(cgImage: cgImage) } .
לוגו במרכז. רמת תיקון H מאפשרת כיסוי של עד 30% משטח הקוד. גודל לוגו של ~25% עובד באופן אמין. חפיפה עם CIQRCodeGenerator:
func addLogo(_ logo: UIImage, to qrImage: UIImage) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: qrImage.size)
return renderer.image { _ in
qrImage.draw(in: CGRect(origin: .zero, size: qrImage.size))
let logoSize = CGSize(width: qrImage.size.width * 0.25, height: qrImage.size.height * 0.25)
let logoOrigin = CGPoint(
x: (qrImage.size.width - logoSize.width) / 2,
y: (qrImage.size.height - logoSize.height) / 2
)
logo.draw(in: CGRect(origin: logoOrigin, size: logoSize))
}
}מודולים מעוגלים דורשים ניתוח של מטריצת הביטים וציור ידני של כל מודול באמצעות CIFalseColor. חבילת ה-Swift של QRCode עושה זאת ומאפשרת התאמה אישית נרחבת.
Android: ZXing ו-ML Kit
ZXing הוא התקן בפועל:
import com.google.zxing.BarcodeFormat
import com.google.zxing.qrcode.QRCodeWriter
fun generateQRCode(content: String, size: Int): Bitmap {
val writer = QRCodeWriter()
val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size)
val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565)
for (x in 0 until size) {
for (y in 0 until size) {
bitmap.setPixel(x, y, if (bitMatrix[x, y]) Color.BLACK else Color.WHITE)
}
}
return bitmap
}לצבעים מותאמים אישית, החליפו את UIGraphicsImageRenderer/H. ללוגו, חפיפה באמצעות UIGraphicsImageRenderer:
fun addLogoToBitmap(qrBitmap: Bitmap, logo: Bitmap): Bitmap {
val result = qrBitmap.copy(Bitmap.Config.ARGB_8888, true)
val canvas = Canvas(result)
val logoSize = qrBitmap.width / 4
val left = (qrBitmap.width - logoSize) / 2f
val top = (qrBitmap.height - logoSize) / 2f
val scaledLogo = Bitmap.createScaledBitmap(logo, logoSize, logoSize, true)
canvas.drawBitmap(scaledLogo, left, top, null)
return result
}ML Kit Barcode Scanning הוא של Google ותומך במספר פורמטים (QR, EAN, Code 128, Data Matrix). הוא מיועד לסריקה בלבד, אבל משמש לעיתים קרובות לצד יצירה.
מקרה בוחן: קוד QR לתפריט מסעדה
מסעדה אחת פנתה אלינו עם קוד QR סטטי שלא היה ניתן לסריקה לאחר הדפסה עם לוגו גדול. יצרנו מחדש את הקוד עם רמת תיקון H והקטנו את הלוגו ל-25% משטח הקוד. בדיקות על 50 מכשירים הראו קריאות של 99.5% אפילו בתאורה חלשה. התיקון לקח יומיים.
למה רמת תיקון H חשובה
רמה H משחזרת עד 30% מהנתונים. זה קריטי כשממקמים לוגו על קוד QR. ללא תיקון מספק, אפילו תמונה קטנה יכולה לשבור את הקריאות. אנחנו משתמשים ב-H בכל פרויקט עם לוגו; לקודי QR רגילים, M או L מספיקים.
הבטחת קריאות עם לוגו
מלבד H, שמרו על שוליים לבנים (אזור שקט) של לפחות 4 מודולים סביב הקוד. גודל הלוגו לא יעלה על 25% משטח הקוד. הבדיקות שלנו על 50 מכשירים מראות קריאות של 99.5% תחת כללים אלה.
השוואה בין QR סטטי לדינמי
| תכונה | QR סטטי | QR דינמי |
|---|---|---|
| כתובת URL | מוגדרת מראש | ניתנת לשינוי דרך השרת |
| תגי UTM | קבועים | דינמיים |
| אנליטיקה | אין מובנית | יומני שרת זמינים |
| אורך חיים | בלתי מוגבל | כל עוד שרת ההפניה פעיל |
| יצירה | לקוח או שרת | בצד השרת, תמונה נשמרת במטמון ב-CDN |
לשיווק, קודי QR דינמיים מציעים גמישות ואנליטיקה. בלקוח הנייד, הם מציגים רק PNG מוכן או תג func addLogo(_ logo: UIImage, to qrImage: UIImage) -> UIImage { let renderer = UIGraphicsImageRenderer(size: qrImage.size) return renderer.image { _ in qrImage.draw(in: CGRect(origin: .zero, size: qrImage.size)) let logoSize = CGSize(width: qrImage.size.width * 0.25, height: qrImage.size.height * 0.25) let logoOrigin = CGPoint( x: (qrImage.size.width - logoSize.width) / 2, y: (qrImage.size.height - logoSize.height) / 2 ) logo.draw(in: CGRect(origin: logoOrigin, size: logoSize)) } } דרך WebView.
שמירה ושיתוף
iOS: שמירה לגלריה דרך UIBezierPath או import com.google.zxing.BarcodeFormat import com.google.zxing.qrcode.QRCodeWriter fun generateQRCode(content: String, size: Int): Bitmap { val writer = QRCodeWriter() val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size) val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565) for (x in 0 until size) { for (y in 0 until size) { bitmap.setPixel(x, y, if (bitMatrix[x, y]) Color.BLACK else Color.WHITE) } } return bitmap } . דורש Color.BLACK. שיתוף דרך Color.WHITE עם Canvas.
Android 10+: השתמשו ב-fun addLogoToBitmap(qrBitmap: Bitmap, logo: Bitmap): Bitmap { val result = qrBitmap.copy(Bitmap.Config.ARGB_8888, true) val canvas = Canvas(result) val logoSize = qrBitmap.width / 4 val left = (qrBitmap.width - logoSize) / 2f val top = (qrBitmap.height - logoSize) / 2f val scaledLogo = Bitmap.createScaledBitmap(logo, logoSize, logoSize, true) canvas.drawBitmap(scaledLogo, left, top, null) return result } דרך <img> (ללא UIImageWriteToSavedPhotosAlbum). שיתוף דרך PHPhotoLibrary.shared().performChanges עם URI באמצעות NSPhotoLibraryAddUsageDescription.
מה כלול בעבודה שלנו
- קוד מקור למודול יצירה והתאמה אישית
- תיעוד API ומדריך אינטגרציה
- הגדרת backend לקודי QR דינמיים (אם נדרש)
- בדיקות על 5+ דגמי מכשירים אמיתיים
- פריסה ל-App Store / Google Play (TestFlight, Google Play Console)
תהליך ולוחות זמנים
- איסוף דרישות – הבנת מקרה השימוש, הנחיות המותג, מגבלות גודל.
- אב טיפוס – יצירת קוד QR לדוגמה עם לוגו, בדיקת קריאות.
- פיתוח – הטמעת מודול עם רמת ההתאמה האישית שנבחרה.
- בדיקות – אימות על מספר מכשירים ותנאי תאורה.
- מסירה – מתן קוד ותיעוד.
יצירה בסיסית: יום עסקים אחד. סגנון מותאם אישית עם לוגו ו-backend דינמי: 2–3 ימים. העלות נקבעת לאחר ניתוח.
המהנדסים שלנו השלימו מעל 50 פרויקטים עם יצירת QR—מכרטיסי ביקור פשוטים ועד קמפיינים שיווקיים ממותגים. אם אתם צריכים קוד QR עם דרישות לא סטנדרטיות, צרו קשר להערכה. הזמינו אינטגרציה של מודול QR—זה לוקח מיום אחד.







