Реализация генерации QR-кодов в мобильном приложении
QR-код генерируется встроенными средствами обеих платформ без сторонних библиотек. На iOS — CIFilter, на Android — ZXing или ML Kit. Сложность не в генерации, а в кастомизации: логотип в центре, фирменные цвета, округлые углы модулей — всё это требует ручной работы с CoreGraphics или Android Canvas.
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 всегда генерирует чёрно-белый QR. Для цветного — заменить белый фон и чёрные модули через CIFalseColor filter, или рисовать поверх через UIGraphicsImageRenderer.
Логотип в центре. Уровень коррекции H (30%) позволяет перекрыть до 30% площади QR-кода без потери считываемости. Логотип размером ~25% от QR работает надёжно. Накладывается через UIGraphicsImageRenderer:
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))
}
}
Округлые модули и точечный стиль — CIFilter этого не умеет. Нужно парсить битовую матрицу QR и рисовать каждый модуль вручную через UIBezierPath. Библиотека QRCode (Swift Package) делает это и даёт широкие возможности кастомизации.
Android: ZXing и ML Kit
ZXing — де-факто стандарт для QR на Android:
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:
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 и UTM-метки
QR с фиксированным URL — статический. QR, который ведёт на редирект-сервис (короткая ссылка, которую можно изменить без перегенерации QR) — динамический. Для маркетинга: каждый QR-код уникален, содержит UTM-метки, аналитика переходов. Генерация на сервере через библиотеку (python-qrcode, qrcode npm) с сохранением PNG в CDN.
На мобильном клиенте в этом случае — только отображение готового PNG или <img> тег через WebView.
Сохранение и шеринг
Сохранить в галерею: на iOS — UIImageWriteToSavedPhotosAlbum или PHPhotoLibrary.shared().performChanges. Требует разрешения NSPhotoLibraryAddUsageDescription. На Android 10+: MediaStore.Images.Media.insertImage через ContentResolver, без разрешения WRITE_EXTERNAL_STORAGE.
Поделиться: UIActivityViewController с UIImage (iOS), Intent.ACTION_SEND с URI через FileProvider (Android).
1 рабочий день для базовой генерации. Кастомный стиль модулей, логотип, брендирование — 2–3 дня. Стоимость рассчитывается индивидуально.







