AppClipsStudio
توجيه الاستدعاء (invocation routing)، وفحوصات الحجم (size checks)، وربط الموقع (website association) لـ iOS App Clips.
الترخيص: MIT
حزمة Swift لـ App Clips في iOS والتطبيقات الكاملة التي تتبعها. تتحقق من صحة invocation URL التي يمرّرها النظام عند الإقلاع وتوجّهها إلى شاشاتك بالطريقة التي يوجّه بها App Store Connect تجارب App Clip، وتتأكد من أن الشخص في موضع الكود، وتُسلِّم بيانات App Clip إلى التطبيق الكامل. أداة سطر الأوامر appclipstudio التابعة لها تفحص حجم كل variant، وApp Clip Code URLs، وملف apple-app-site-association، وإدخالات Associated Domains قبل الرفع. بلا اعتماديات (dependencies).
الميزات
- توجيه الاستدعاء بقاعدة مطابقة Apple: أنماط مثل /table/:number و/shop/*، أكثر prefix تحديدًا يفوز، يمكن لـ handler رفض مطابقة، وfallback يغطي بقية prefix مسجَّل
- المدخلات غير الموثوقة تبقى محدودة: https فقط، 2,048 بايت كحد أقصى، 32 مكوّن path و64 عنصر query، بلا مكوّنات . أو ..، وبلا أحرف تحكم (control) أو تنسيق (format) في host وpath وquery بعد فك التشفير (decoding)
- فحوصات الحجم لكل variant: حدود Apple البالغة 10 و15 و100 MB تُطبَّق على ملف Xcode's App Thinning Size Report.txt حسب إصدار iOS وdeployment target ونوع الاستدعاء، مع exit status لـ CI
- ربط الموقع (website association): توليد وتحقق من صحة apple-app-site-association، وفحص إدخالات entitlement من نوع appclips: وapplinks:، وفحص App Clip Code URLs مقابل قواعد Apple
- HandoffStore يُمرِّر قيمة Codable مُرقَّمة الإصدار (versioned) وقابلة للانتهاء ومحدودة الحجم إلى التطبيق الكامل عبر App Group المشترك
- تأكيد الموقع الجغرافي بمنطقة مُتحقَّق منها لا تتجاوز 500 متر، وoverlay الخاص بـ App Store للتطبيق الكامل
- تطبيق مثال وApp Clip (Examples/CoffeeShop) مبنيان من مصادر مشتركة؛ CI يبنيهما وأمثلة README مأخوذة منهما
البدء السريع
1import AppClipsStudio2import SwiftUI3 4enum Screen: Equatable {5 case welcome6 case table(Int)7}8 9struct ContentView: View {10 @State private var screen = Screen.welcome11 12 var body: some View {13 Group {14 switch screen {15 case .welcome: Text("Scan a table tag")16 case .table(let number): Text("Table \(number)")17 }18 }19 .font(.largeTitle)20 .onInvocation { invocation in21 screen = (try? Self.router.route(invocation)) ?? .welcome22 }23 }24 25 static let router: InvocationRouter<Screen> = {26 var router = InvocationRouter<Screen>()27 try? router.add("/table/:number") { match in28 match.integer("number").map(Screen.table)29 }30 router.fallback { _ in .welcome }31 return router32 }()33}التثبيت
Swift Package Manager
1dependencies: [2 .package(url: "https://github.com/muhittincamdali/AppClipsStudio.git", from: "2.0.0")3],4targets: [5 .target(name: "YourAppFeature", dependencies: [6 .product(name: "AppClipsStudio", package: "AppClipsStudio")7 ])8]Xcode
1https://github.com/muhittincamdali/AppClipsStudio.gitCommand-line tool
1git clone https://github.com/muhittincamdali/AppClipsStudio.git2cd AppClipsStudio3swift build -c release4cp .build/release/appclipstudio /usr/local/bin/ # or run it with `swift run appclipstudio`لقطات الشاشة




الجدول الزمني
فُتح المستودع كـ framework معياري (modular) لـ App Clip
وُسم v1.0.0؛ عمل على الدوكيومنتيشن وCI، بينما بقيت مصادر الوحدات (modules) placeholder
تنظيف: دُمجت الوحدات في target واحد من بضعة stubs
أُعيد البناء كـ 2.0.0 بالاستناد إلى دوكيومنتيشن Apple لـ App Clip: توجيه الاستدعاء، وفحوصات الحجم، وربط الموقع، وCLI الخاص بـ appclipstudio؛ لم يُحتفَظ بأي API من 1.0.0