צילום מסך עם הערות והקשר: מודול משוב בתוך האפליקציה לאפליקציות מובייל
משתמש מדווח על באג: "הכפתור לא עובד." המפתח תוהה: איזה כפתור? באיזה מסך? משוב בתוך האפליקציה מסיר את כל השאלות — המשתמש ממש מראה את הבעיה על צילום מסך, מסמן אותה עם מרקר, ומוסיף תגובה. אנו מיישמים מודול כזה במפתחות מלאה: מצילום מסך ועד שליחה ל-Jira או Sentry. בפרויקט אחד עם קהל של מיליון משתמשים, יישום מודול זה חצה את זמן ניתוח הבאגים הראשוני, ומספר התקלות הניתנות לשחזור גדל ב-70%.
אתגרים אופייניים: חוסר הקשר (צילום מסך נותן פי 10 יותר מידע מטקסט), מטא-דאטה לא מלא (גרסה, מערכת הפעלה, מכשיר), חוסר יכולת לשחזר את הבאג (צילום מסך לוכד את המצב). הפתרון שלנו מצרף אוטומטית את כל המטא-דאטה ושומר את צילום המסך למערכת המעקב. אנו משתמשים בגישות מוכחות ומבטיחים ביצועים — צילום המסך נוצר בפחות מ-0.5 שניות. מניסיוננו, יישום מודול כזה מפחית את זמן הניפוי ב-60% וחוסך עד 40 שעות של עבודת מהנדס בחודש.
למה משוב בתוך האפליקציה הוא קריטי לאפליקציות מובייל
ללא צילום מסך עם הקשר, מפתח מבלה בממוצע 20 דקות בבירור פרטי הבאג. משוב בתוך האפליקציה מפחית זמן זה לאפס: כל המידע (תמונה, הערות, מטא-דאטה) מגיע למערכת הכרטוס בלחיצה אחת. זה חשוב במיוחד לאפליקציות עם דינמיקה גבוהה — לדוגמה, פינטק או לוגיסטיקה, שבהן כל שעת השבתה עולה כסף.
איך לצלם מסך ב-iOS וב-Android
כל פלטפורמה דורשת גישה משלה. אנו משלבים שיטות לכיסוי מקסימלי.
iOS — UIGraphicsImageRenderer + WKWebView
func captureScreenshot() -> UIImage? {
let renderer = UIGraphicsImageRenderer(bounds: UIScreen.main.bounds)
return renderer.image { ctx in
UIApplication.shared.windows.first?.layer.render(in: ctx.cgContext)
}
}
// Для WKWebView: webView.takeSnapshot(with: nil) { image, error in
// Вставить в итоговый скриншот через Core Graphics }לפרטים נוספים: UIGraphicsImageRenderer. נקודה חשובה: func captureScreenshot() -> UIImage? { let renderer = UIGraphicsImageRenderer(bounds: UIScreen.main.bounds) return renderer.image { ctx in UIApplication.shared.windows.first?.layer.render(in: ctx.cgContext) } } // Для WKWebView: webView.takeSnapshot(with: nil) { image, error in // Вставить в итоговый скриншот через Core Graphics } לא לוכד תוכן מ-WKWebView ו-ARSCNView — הם מרנדרים דרך הקשר GPU נפרד. לכן, עבור WebView אנו משתמשים בשיטת layer.render.
Android — PixelCopy API
fun captureScreenshot(activity: Activity, callback: (Bitmap?) -> Unit) {
val bitmap = Bitmap.createBitmap(
activity.window.decorView.width,
activity.window.decorView.height,
Bitmap.Config.ARGB_8888
)
PixelCopy.request(activity.window, bitmap, { result ->
callback(if (result == PixelCopy.SUCCESS) bitmap else null)
}, Handler(Looper.getMainLooper()))
}מדריך המפתחים של Android ממליץ על PixelCopy החל מ-Android 8.0 (API 26). עבור מכשירים ישנים יותר, אנו משתמשים ב-takeSnapshot(with:), אך הוא לא לוכד SurfaceView.
| פלטפורמה | שיטה | מגבלות |
|---|---|---|
| iOS | UIGraphicsImageRenderer | לא לוכד WKWebView ו-ARSCNView |
| Android | PixelCopy (API 26+) | לא לוכד SurfaceView |
| Flutter | RenderRepaintBoundary | עובד רק בתוך ווידג'טים של Flutter |
למה כלי סימון מותאם אישית עדיף על פתרונות מוכנים
ספריות מוכנות (PSPDFKit, Pen) חוסכות זמן אך מגבילות שליטה. כלי סימון מותאם אישית מספק 40% יותר גמישות ואין לו הגבלות רישוי. פיתוח כלי סימון משלך לוקח 2–3 ימים ונותן שליטה מלאה על חוויית המשתמש. בפרויקט אחד, החלפנו את PSPDFKit בקנבס מותאם אישית והשגנו:
- צורות חצים מותאמות (קו כפול, מעוקל)
- פיקסלציה לפי אזור (הסתרת מידע אישי)
- תגובת מגע מיידית (ללא עיכובי UIKit)
דוגמה לקנבס מותאם אישית
class AnnotationCanvasView: UIView {
private var paths: [UIBezierPath] = []
private var currentPath: UIBezierPath?
var strokeColor: UIColor = .red
var strokeWidth: CGFloat = 3.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let path = UIBezierPath()
path.move(to: touches.first!.location(in: self))
currentPath = path
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
currentPath?.addLine(to: touches.first!.location(in: self))
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let path = currentPath {
paths.append(path)
}
currentPath = nil
}
override func draw(_ rect: CGRect) {
for path in paths {
strokeColor.setStroke()
path.lineWidth = strokeWidth
path.stroke()
}
strokeColor.setStroke()
currentPath?.stroke()
}
} | קריטריון | SDK מוכן | יישום מותאם אישית |
|---|---|---|
| זמן אינטגרציה | 1–2 ימים | 2–3 ימים |
| שליטה על חוויית המשתמש | מוגבלת | מלאה |
| רישוי | בתשלום (SDK) | חינם |
| התאמה אישית | דרך API | כל דבר |
איסוף מטא-דאטה
אנו מצרפים אוטומטית את הדברים הבאים לצילום המסך:
struct FeedbackPayload: Encodable {
let screenshot: Data // JPEG, качество 0.7
let description: String
let appVersion: String
let osVersion: String
let deviceModel: String
let screenName: String // текущий экран (роутер/NavigationStack)
let userId: String?
let sessionId: String // UUID сессии для корреляции с логами
let timestamp: Date
}fun captureScreenshot(activity: Activity, callback: (Bitmap?) -> Unit) { val bitmap = Bitmap.createBitmap( activity.window.decorView.width, activity.window.decorView.height, Bitmap.Config.ARGB_8888 ) PixelCopy.request(activity.window, bitmap, { result -> callback(if (result == PixelCopy.SUCCESS) bitmap else null) }, Handler(Looper.getMainLooper())) } חשוב במיוחד — הוא מאפשר למפתחים לדעת מיד באיזה מסך התרחשה הבעיה מבלי לשאול את המשתמש.
איך לשלוח משוב למערכת הכרטוס
אנו שולחים את צילום המסך כ-multipart/form-data. לאחסון בקצה האחורי, אנו משתמשים ב-S3 או דומה עם כתובות URL חתומות מראש. במערכת הכרטוס (Jira, Linear, Sentry), אנו מצרפים קישור לתמונה.
דוגמה דרך Sentry:
let attachment = Attachment(
data: screenshotData,
filename: "screenshot.jpg",
contentType: "image/jpeg"
)
SentrySDK.capture(message: feedback.description) { scope in
scope.addAttachment(attachment)
scope.setTag(value: feedback.screenName, key: "screen")
} דוגמה להגדרת Sentry עבור iOS
```swift SentrySDK.start { options in options.dsn = "https://[email protected]/0" options.enableAutoPerformanceTracking = true } ```תהליך עבודה
- ניתוח — אנו בודקים את תהליך איסוף הבאגים הנוכחי, מזהים צווארי בקבוק.
- עיצוב — אנו בוחרים את שיטת הצילום, מעצבים את חוויית הסימון.
- פיתוח — אנו מיישמים את המודול, משתלבים עם מערכת ה-CRM/כרטוס שלך.
- בדיקות — בדיקות עומס (100+ צילומי מסך לדקה), אימות פרטיות (פיקסלציה).
- פריסה — תיעוד, הדרכת צוות, ניטור.
מה כלול
- מסמך ארכיטקטוני המתאר את המודול
- SDK ללא התנגשויות עם תלויות קיימות
- אינטגרציה עם Jira, Sentry, או מערכת ה-CRM שלך
- הוראות למשתמש
- הבטחת ביצועים (צילום מסך < 1 שנייה)
- הדרכת צוות
הערכות זמן ועלות
לצוות שלנו ניסיון רב בפיתוח מובייל, לאחר שיישם למעלה מ-15 פרויקטים עם משוב בתוך האפליקציה. יישום מותאם אישית לוקח 1–1.5 שבועות. אינטגרציה של ספרייה מוכנה לוקחת 3–5 ימים. העלות מחושבת באופן אישי ותלויה במורכבות האינטגרציה. צור קשר להערכת פרויקט — נציע את הפתרון האופטימלי. הזמינו ייעוץ על שילוב משוב בתוך האפליקציה באפליקציה שלכם.







