आईओएस एसडीके: सर्वाइविंग सस्पेंशन
Apple का CoreLocation फ्रेमवर्क बैकग्राउंड ट्रैकिंग के लिए शक्तिशाली उपकरण प्रदान करता है, लेकिन iOS मेमोरी और बैटरी जीवन को बचाने के लिए ऐप्स को निलंबित करने में बेहद आक्रामक है।
यह पृष्ठ सटीक रूप से बताता है कि ट्रैसलेट ऐप्पल की सख्त पृष्ठभूमि निष्पादन नीतियों के साथ कैसे इंटरैक्ट करता है, और आप इसे अपने विशिष्ट परिदृश्य के लिए कैसे कॉन्फ़िगर कर सकते हैं।
अनुमतियाँ और जानकारी.प्लिस्ट सेटअप
Apple सख्त गोपनीयता आवश्यकताओं को लागू करता है। ट्रेसलेट का प्रभावी ढंग से उपयोग करने के लिए, आपको अपने ios/Runner/Info.plist में सटीक क्यों कुछ अनुमतियों की आवश्यकता है, इसकी घोषणा करनी होगी। यदि ये स्ट्रिंग्स गायब हैं या उपयोग-मामले को स्पष्ट रूप से स्पष्ट नहीं करते हैं, तो ऐप स्टोर समीक्षा के दौरान ऐप्पल आपके ऐप को अस्वीकार कर देगा।
1. आवश्यक उपयोग विवरण
अपने Info.plist में निम्नलिखित कुंजियाँ जोड़ें:
<!-- Required for basic tracking -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to track your route while the app is open.</string>
<!-- Required for background tracking when the app is minimized or killed -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need background location to record your route even when the app is closed.</string>
<!-- Required for the smart motion-detection battery saving engine -->
<key>NSMotionUsageDescription</key>
<string>Motion detection allows battery-efficient tracking by pausing GPS when stationary.</string>2. पृष्ठभूमि मोड
ट्रैसलेट को पृष्ठभूमि में चलाने के लिए (और ऐप बंद होने पर हेडलेस डार्ट कोड निष्पादित करने के लिए), आपको Xcode में उचित पृष्ठभूमि मोड क्षमताओं की घोषणा करनी होगी।
वैकल्पिक रूप से, उन्हें सीधे अपने Info.plist में जोड़ें:
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>fetch</string>
<!-- Only add 'audio' if you are using 'preventSuspend: true' (See Scenario 1 below) -->
</array>3. वैकल्पिक सुविधाएँ हटाना (कोई क्रैश नहीं)
यदि आपका ग्राहक विशिष्ट सुविधाएँ नहीं चाहता है (उदाहरण के लिए, वे गति या गतिविधि प्रकारों को ट्रैक नहीं करना चाहते हैं), तो आप अपने Info.plist से संबंधित कुंजी को सुरक्षित रूप से हटा सकते हैं। ट्रैसलेट का मूल स्विफ्ट कोड सुविधाओं का अनुरोध करने से पहले मुख्य उपस्थिति की सुरक्षित रूप से जांच करता है।
| फ़ीचर कुंजी | Info.plist से हटाए जाने पर प्रभाव |
|---|---|
NSMotionUsageDescription | सुरक्षित। iOS चुपचाप मूवमेंट के लिए स्थान परिवर्तन की जाँच करेगा। CMMotionActivityManager लागू नहीं किया जाएगा, और उपयोगकर्ता को मोशन अनुमतियों के लिए संकेत नहीं दिया जाएगा। |
UIBackgroundModes -> audio | सुरक्षित। केवल तभी आवश्यक है जब आपका कॉन्फिगरेशन डार्ट आइसोलेट सस्पेंशन को रोकने के लिए preventSuspend: true सेट करता है। |
NSLocationAlwaysAndWhenInUseUsageDescription | सुरक्षित। ऐप केवल अग्रभूमि में (या अस्थायी रूप से नीली गोली के माध्यम से) ट्रैक करेगा। ट्रेसलेट आंतरिक रूप से सुंदर गिरावट को संभालता है। |
परिदृश्य 1: फिटनेस ऐप (उच्च सटीकता, कोई निलंबन नहीं)
अवधारणाओं की खोज: गतिविधि प्रकार, सस्पेंशन, ऑडियो वेक
समस्या
आपका उपयोगकर्ता मैराथन दौड़ रहा है. वे आपका ऐप खोलते हैं, रन शुरू करते हैं और अपना आईफोन लॉक कर देते हैं। पांच मिनट बाद, iOS निर्णय लेता है कि उसे बैकग्राउंड iCloud बैकअप चलाने के लिए RAM की आवश्यकता है, इसलिए यह आपके ऐप के डार्ट आइसोलेट को पूरी तरह से निलंबित कर देता है। ट्रैसलेट का मूल स्विफ्ट कोड जीपीएस पॉइंट इकट्ठा करना जारी रखता है, लेकिन क्योंकि डार्ट आइसोलेट जम गया है, आपका फ़्लटर यूआई दूरी काउंटर को अपडेट करना बंद कर देता है, और डार्ट में आपके द्वारा चलाए जा रहे सभी लाइव-ट्रैकिंग वेब-सॉकेट बंद हो जाते हैं।
ट्रेसलेट इसे कैसे हल करता है: निलंबन रोकें
स्क्रीन बंद होने पर फ़्लटर डार्ट आइसोलेट को अनिश्चित काल तक चालू रखने के लिए, आपको iOS को यह सोचकर धोखा देना होगा कि ऐप सक्रिय रूप से मीडिया चला रहा है।
ios: tl.IosConfig(
activityType: tl.LocationActivityType.fitness, // Optimizes GPS filtering for running
preventSuspend: true,
)preventSuspend: true को सेट करने से ट्रैसलेट एक लूप पर एक अगोचर, मूक ऑडियो क्लिप चलाता है। क्योंकि iOS को लगता है कि उपयोगकर्ता संगीत सुन रहा है, यह कभी भी डार्ट आइसोलेट को निलंबित नहीं करेगा।
ऐप स्टोर समीक्षा नोट: preventSuspend का उपयोग करने के लिए Xcode में audio पृष्ठभूमि मोड क्षमता की आवश्यकता होती है। यदि आप किसी वैध उपयोगकर्ता-सामना वाले कारण के बिना ऐप को सक्रिय रखने के लिए पृष्ठभूमि ऑडियो का उपयोग करते हैं, तो Apple आपके ऐप को अस्वीकार कर देगा (उदाहरण के लिए, एक फिटनेस ट्रैकर ध्वनि संकेत बजा रहा है, या एक नेविगेशन ऐप जो बारी-बारी से दिशानिर्देश बोल रहा है)। मूक बेड़े ट्रैकिंग के लिए इसका उपयोग न करें!
इसे सक्षम करने के लिए: अपने iOS प्रोजेक्ट को Xcode में खोलें, साइनिंग और क्षमताएं -> + क्षमता -> बैकग्राउंड मोड -> ऑडियो, एयरप्ले और पिक्चर इन पिक्चर चेक करें।
परिदृश्य 2: सामाजिक रडार (कम शक्ति, मोटे)
अवधारणाओं की खोज: महत्वपूर्ण परिवर्तन, प्राधिकरण स्तर
समस्या
आप एक सोशल नेटवर्किंग ऐप बना रहे हैं जो किसी मित्र के पास होने पर उपयोगकर्ता को सूचित करता है। आपको बारी-बारी सटीकता की आवश्यकता नहीं है; आपको बस मोटे तौर पर यह जानना होगा कि वे किस पड़ोस में हैं। आप डरावना “हमेशा अनुमति दें” अनुमति संकेत भी नहीं दिखाना चाहेंगे, क्योंकि उपयोगकर्ता इसे अस्वीकार कर देंगे।
ट्रेसलेट इसे कैसे हल करता है: महत्वपूर्ण परिवर्तन
जीपीएस चिप को पावर देने के बजाय, ट्रैसलेट पूरी तरह से सेल-टावर हैंडऑफ़ पर भरोसा कर सकता है।
ios: tl.IosConfig(
useSignificantChangesOnly: true,
locationAuthorizationRequest: tl.LocationAuthorizationRequest.whenInUse,
disableLocationAuthorizationAlert: true,
)- केवल महत्वपूर्ण परिवर्तन: इसे सक्षम करके, ट्रैसलेट आईओएस को ऐप को केवल तभी सक्रिय करने के लिए कहता है जब डिवाइस पूरी तरह से अलग सेल टावर (आमतौर पर 500 मीटर से कई किलोमीटर) पर पहुंच जाता है। बैटरी की खपत व्यावहारिक रूप से शून्य है।
- जब उपयोग में हो प्राधिकरण: आप केवल “जब उपयोग में हों” अनुमति मांगते हैं। ट्रैसलेट इसका सम्मान करता है और उपयोगकर्ता को “हमेशा” सक्षम करने के लिए सेटिंग्स पर जाने के लिए कहने वाले मूल ऐप्पल प्रॉम्प्ट को ट्रिगर नहीं करेगा। (डार्ट से इन अनुमति संकेतों को ट्रिगर करने का तरीका जानने के लिए, स्पंदन एसडीके: अनुमतियाँ पृष्ठ देखें)।
परिदृश्य 3: नीला स्थान संकेतक (showsBackgroundLocationIndicator)
अवधारणाओं की खोज: पृष्ठभूमि स्थान संकेतक
यह झंडा असल में क्या करता है
showsBackgroundLocationIndicator सीधे एप्पल के लिए मैप करता है
CLLocationManager.showsBackgroundLocationIndicator। नाम प्रति-सहज ज्ञान युक्त है - यह संकेतक को दिखाने के लिए एक ऑप्ट-इन है, इसे छिपाने के लिए एक स्विच नहीं:
| मूल्य | मतलब |
|---|---|
true | जब ऐप पृष्ठभूमि में स्थान का उपयोग करता है तो नीला स्टेटस-बार पिल/डायनेमिक आइलैंड संकेतक दिखाएँ। |
false (डिफ़ॉल्ट) | पृष्ठभूमि स्थान उपयोग के लिए संकेतकछिपाने का अनुरोध। |
सामान्य ग़लतफ़हमी: showsBackgroundLocationIndicator: true सेट करने से नीला संकेतक *बंद नहीं होता है - यह इसे चालू हो जाता है। यदि आपका लक्ष्य इसे छिपाना है, तो इसे false (डिफ़ॉल्ट) छोड़ दें। इसे true सेट करना केवल तभी उपयोगी है जब आप चाहते हैं कि गोली दिखाई दे (उदाहरण के लिए, नीचे “जब उपयोग में हो” पृष्ठभूमि ट्रैकिंग को संतुष्ट करने के लिए)।
जब आप गोली चाहते हैं (“जब उपयोग में हो” पर अस्थायी पृष्ठभूमि ट्रैकिंग)
आपके पास केवल “जब उपयोग में हो” की अनुमति है, लेकिन जब तक उपयोगकर्ता कोई कार्य पूरा कर लेता है (उदाहरण के लिए राइडशेयर पिकअप) आप ट्रैकिंग करते रहना चाहते हैं। iOS इसकी अनुमति देता है केवल तभी जब संकेतक दिखाई दे, ताकि उपयोगकर्ता को पता चले कि ट्रैकिंग हो रही है:
ios: tl.IosConfig(
showsBackgroundLocationIndicator: true,
)इसे सक्षम करने के लिए: location बैकग्राउंड मोड Xcode में चालू होना चाहिए (हस्ताक्षर और क्षमताएं → बैकग्राउंड मोड → स्थान अपडेट)।
false इसे हमेशा क्यों नहीं छिपाता?
showsBackgroundLocationIndicator: false के साथ भी, iOS इन मामलों में संकेतक को बलपूर्वक चालू करता है - ध्वज उन्हें ओवरराइड नहीं कर सकता है:
- “जब उपयोग में हो” प्राधिकरण - पृष्ठभूमि स्थान हमेशा संकेतक दिखाता है। केवल पूर्ण “हमेशा” प्राधिकरण ही इसे दबा सकता है।
useBackgroundActivitySession: true(iOS 17+) -CLBackgroundActivitySessionसक्रिय होने पर Apple को संकेतक की आवश्यकता होती है (परिदृश्य 4)।- लाइव गतिविधियां सक्रिय (परिदृश्य 5)।
- कोई भी निरंतर पृष्ठभूमि स्थान सत्र - यदि ऐप
startUpdatingLocationनॉन-स्टॉप चल रहा है, तो संकेतक ध्वज की परवाह किए बिना चालू रहता है।
वास्तव में सूचक को छिपाकर रखना
- पूर्ण “हमेशा” प्राधिकरण प्राप्त करें (ध्यान दें कि iOS पहले एक अनंतिम “जब उपयोग में हो” दे सकता है जब तक कि उपयोगकर्ता बाद में “हमेशा में बदलें” की पुष्टि नहीं करता - गोली तब तक दिखाई देती है)।
showsBackgroundLocationIndicator: falseरखें (इसेtrueपर सेट न करें)।- अनावश्यक निरंतर पृष्ठभूमि स्थान से बचें। जियोफेंस‑ओनली मोड मूल क्षेत्र निगरानी (कोई निरंतर जीपीएस नहीं) का उपयोग करता है, इसलिए यह कोई संकेतक नहीं दिखाता है -
startGeofences()मानक मोड में निरंतर अपडेट नहीं चलाता है।
परिदृश्य 4: डायनेमिक आइलैंड संकेतक (iOS 17+)
अवधारणाओं की खोज: पृष्ठभूमि गतिविधि सत्र
समस्या
आप ब्लू पिल इंडिकेटर के लाभ चाहते हैं, लेकिन आप आधुनिक आईफ़ोन पर डायनेमिक आइलैंड के साथ अधिक आधुनिक, देशी एकीकरण चाहते हैं, और आप ओएस द्वारा आपके पृष्ठभूमि सत्र को ख़त्म करने की संभावना को कम करना चाहते हैं।
ट्रेसलेट इसे कैसे हल करता है
ट्रैसलेट Apple के CLBackgroundActivitySession (iOS 17 में प्रस्तुत) के साथ एकीकृत होता है। यह एक प्रमुख डायनेमिक आइलैंड संकेतक प्रदान करता है और ओएस के साथ एक औपचारिक सत्र बनाता है, जो बताता है कि आपके ऐप को निलंबित न करें।
ios: tl.IosConfig(
useBackgroundActivitySession: true,
)ऐप स्टोर समीक्षा आवश्यकताएँ: Apple को स्पष्ट रूप से इस बात की स्पष्ट व्याख्या की आवश्यकता है कि आपके ऐप को लगातार पृष्ठभूमि स्थान की आवश्यकता क्यों है। यदि आप CLBackgroundActivitySession का उपयोग करते हैं, तो आपको तीन स्थानों पर औचित्य प्रदान करना होगा, अन्यथा आपका ऐप अस्वीकार कर दिया जाएगा:
- ऐप स्टोर कनेक्ट समीक्षा नोट्स: आपको समीक्षक को इस बारे में स्पष्ट लिखित स्पष्टीकरण देना होगा कि ऐप को इस सुविधा की आवश्यकता क्यों है, साथ ही इस सुविधा को क्रियान्वित करने वाले डेमो वीडियो का लिंक भी देना होगा।
- ऐप स्टोर विवरण: आपके सार्वजनिक ऐप विवरण में स्पष्ट रूप से बताया जाना चाहिए कि ऐप पृष्ठभूमि स्थान का उपयोग करता है (उदाहरण के लिए, “यह ऐप ऐप बंद होने पर भी आपके रन को ट्रैक करने के लिए पृष्ठभूमि स्थान का उपयोग करता है।”)।
- इन-ऐप ऑनबोर्डिंग: स्थान अनुमतियों का अनुरोध करने से पहले, आपके ऐप के यूआई को उपयोगकर्ता को स्पष्ट रूप से बताना होगा कि पृष्ठभूमि स्थान की आवश्यकता क्यों है।
परिदृश्य 5: लाइव गतिविधियाँ (लॉक स्क्रीन और डायनेमिक आइलैंड यूआई)
अवधारणाओं की खोज: एक्टिविटीकिट, लॉक स्क्रीन विजेट, डायनेमिक आइलैंड
समस्या
IOS 17+ पर पृष्ठभूमि में ट्रैकिंग करते समय, आप लॉक स्क्रीन और डायनेमिक आइलैंड पर एक समृद्ध, नज़र डालने योग्य संकेतक चाहते हैं - ताकि उपयोगकर्ता को हमेशा पता चले कि ट्रैकिंग सक्रिय है - केवल छोटे नीले स्थान की गोली के बजाय।
ट्रेसलेट इसे कैसे हल करता है
ट्रेसलेट एप्पल के एक्टिविटीकिट के साथ एकीकृत होता है। यदि आप liveActivityConfig प्रदान करते हैं और एक विजेट एक्सटेंशन जोड़ते हैं, तो ट्रैकिंग शुरू होने पर ट्रैसलेट स्वचालित रूप से एक लाइव गतिविधि शुरू कर देता है और ट्रैकिंग बंद होने पर इसे समाप्त कर देता है।
लाइव गतिविधि ट्रेसलेट की मानक पृष्ठभूमि पाइपलाइन के शीर्ष पर एक यूआई परत है। बैटरी की दक्षता गति-पहचान इंजन के स्थिर होने पर जीपीएस को रोकने और पृष्ठभूमि-सत्र एकीकरण (परिदृश्य 4) से आती है - गतिविधि विजेट से नहीं। ट्रैसलेट दूसरी CLLocationUpdate.liveUpdates() स्ट्रीम नहीं खोलता है, जो जीपीएस कार्य की नकल करेगा।
ios: tl.IosConfig(
liveActivityConfig: tl.LiveActivityConfig(
title: 'Ride in progress',
body: 'Tracking your route to the destination...',
),
)ट्रैकिंग के दौरान लाइव गतिविधि को ताज़ा करना (updateNotification())
ट्रैकिंग शुरू होने के बाद में लाइव गतिविधि क्या दिखाती है, इसे बदलने के लिए, liveActivityConfig को setConfig() के माध्यम से अपडेट करें और फिर Tracelet.updateNotification() पर कॉल करें। चूंकि v3.6.8 यह ट्रैकिंग पाइपलाइन को पुनरारंभ किए बिना ** नवीनतम कॉन्फ़िगरेशन से लाइव गतिविधि को रीफ्रेश करता है - एंड्रॉइड फोरग्राउंड-सर्विस अधिसूचना को रीफ्रेश करने के लिए क्रॉस-प्लेटफ़ॉर्म समकक्ष:
await Tracelet.setConfig(
const tl.Config(
ios: tl.IosConfig(
liveActivityConfig: tl.LiveActivityConfig(
title: 'Ride in progress',
body: 'Arriving in 2 minutes',
),
),
),
);
await Tracelet.updateNotification();चल रही गतिविधि पर केवल बॉडी को अपडेट किया जाता है - title अपरिवर्तनीय ActivityAttributes में रहता है और गतिविधि को समाप्त करने और फिर से अनुरोध किए बिना नहीं बदल सकता (एक एक्टिविटीकिट बाधा)।
लाइव गतिविधि चलती उप-स्थिति से बंधी होती है (यह तब खारिज हो जाती है जब ट्रैसलेट स्थिर होने पर जीपीएस को रोक देता है), इसलिए जब आप इसे रीफ्रेश करेंगे तो यह स्क्रीन पर नहीं हो सकता है। जब कोई ट्रैकिंग सत्र सक्रिय होता है, तो updateNotification() आपके लिए इसे संभालता है: यह चल रही गतिविधि को अद्यतन करता है, या इसे नवीनतम सामग्री के साथ पुनः प्रस्तुत करता है यदि इसे खारिज कर दिया गया था। जब कोई liveActivityConfig सेट नहीं होता है या ट्रैकिंग बंद हो जाती है तो यह एक सुरक्षित नो-ऑप है।
Xcode विजेट एक्सटेंशन सेटअप (आवश्यक)
यह किसलिए है? यह सेटअप आपके ऐप को ट्रैकिंग सक्रिय होने पर iOS लॉक स्क्रीन और डायनेमिक आइलैंड पर लाइव गतिविधि प्रदर्शित करने की अनुमति देता है। यह उपयोगकर्ताओं को ऐप खोले बिना उनके चल रहे सत्र के बारे में देखने योग्य जानकारी प्रदान करता है।
क्या इससे बैटरी बचती है? नहीं। लाइव एक्टिविटी पूरी तरह से एक यूआई परत है और बैटरी की बचत नहीं करती है। बैटरी दक्षता पूरी तरह से ट्रैसलेट के मुख्य पृष्ठभूमि इंजन (गति का पता लगाना, स्थिर होने पर जीपीएस को रोकना और पृष्ठभूमि सत्र) से आती है।
क्या यह अनिवार्य है? नहीं. यह सेटअप पूरी तरह से वैकल्पिक है. यदि आप इसे छोड़ देते हैं, तो ट्रैसलेट अभी भी पृष्ठभूमि में पूरी तरह से ट्रैक करेगा, लेकिन उपयोगकर्ताओं को आपके कस्टम यूआई के बजाय केवल मानक सिस्टम संकेतक (जैसे नीली स्थान गोली) दिखाई देंगे।
एंड्रॉइड के विपरीत, फ़्लटर प्लगइन्स गतिशील रूप से iOS विजेट नहीं बना सकते हैं। लाइव गतिविधियों को सक्षम करने के लिए, आपको Xcode में अपने iOS ऐप में एक विजेट एक्सटेंशन लक्ष्य जोड़ना होगा:
- Xcode में
ios/Runner.xcworkspaceखोलें। - फ़ाइल -> नया -> लक्ष्य… पर जाएँ और विजेट एक्सटेंशन चुनें।
- इसे
TraceletWidgetनाम दें। सुनिश्चित करें कि लाइव गतिविधि शामिल करें चेक किया गया है। - आपके ऐप के
Info.plistऔर आपके नए विजेट एक्सटेंशन केInfo.plistदोनों में (Xcode -> Open As -> सोर्स कोड में उन्हें राइट क्लिक करें), आपको **मुख्य<dict>के अंदर निम्नलिखित कुंजी जोड़नी होगी:
<key>NSSupportsLiveActivities</key>
<true/>- एक्सटेंशन संस्करण को सिंक करें (केवल ऐप स्टोर सबमिशन के लिए मायने रखता है): ऐप्पल उस ऐप एक्सटेंशन को अस्वीकार कर देता है जिसका
CFBundleShortVersionString/CFBundleVersionहोस्ट ऐप से मेल नहीं खाता है। अपने ऐप से मेल खाने के लिए विजेट लक्ष्य का संस्करण और बिल्ड सेट करें: ट्रेसलेटविजेट लक्ष्य → सामान्य → पहचान चुनें, और अपने ऐप के संस्करण में संस्करण सेट करें और अपने ऐप के बिल्ड नंबर पर बिल्ड सेट करें (आपकेpubspec.yamlके समान मान)।
विजेट के Info.plist में $(FLUTTER_BUILD_NAME) / $(FLUTTER_BUILD_NUMBER) चिपकाकर इन्हें सेट करने का प्रयास नहीं करें। वे वेरिएबल केवल रनर लक्ष्य के लिए परिभाषित हैं (फ़्लटर के Generated.xcconfig के माध्यम से); विजेट लक्ष्य में वे खाली करने का संकल्प लेते हैं, इसलिए संस्करण चुपचाप मेल नहीं खाएंगे। ऊपर बताए अनुसार लक्ष्य की बिल्ड सेटिंग्स (MARKETING_VERSION / CURRENT_PROJECT_VERSION) का उपयोग करें। यह केवल सबमिशन आवश्यकता है - बेमेल होने से ऐप रनटाइम पर क्रैश नहीं होता है।
- फ़्लटर निर्भरता को लिंक न करें:
FlutterGeneratedPluginSwiftPackageया फ़्लटर इंजन को अपने विजेट एक्सटेंशन से लिंक न करें। ऐसा करने से रिलीज़ मोड में लॉन्च-टाइमdyldक्रैश (Library not loaded) हो जाता है, क्योंकि फ़्लटर अपने गतिशील SPM फ़्रेमवर्क को ऐप एक्सटेंशन में एम्बेड नहीं करता है। - स्वतः उत्पन्न
TraceletWidgetLiveActivity.swiftसामग्री को निम्नलिखित से बदलें। ध्यान दें कि हम SDK को आयात करने के बजाय यहांTraceletActivityAttributesसंरचना को मैन्युअल रूप से परिभाषित करते हैं - एक्टिविटीकिट संरचना के (अयोग्य) नाम और आकार के आधार पर गतिविधि से मेल खाता है, इसलिए यह आपके विजेट को हल्का रखता है और SDK को एक्सटेंशन में लिंक करने से बचाता है:
import ActivityKit
import WidgetKit
import SwiftUI
// Define the exact struct expected by Tracelet's native core
public struct TraceletActivityAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
public var status: String
public init(status: String) { self.status = status }
}
public var title: String
public init(title: String) { self.title = title }
}
@main
struct TraceletWidgetBundle: WidgetBundle {
var body: some Widget {
TraceletWidgetLiveActivity()
}
}
struct TraceletWidgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TraceletActivityAttributes.self) { context in
// Lock Screen / banner UI — fully self-contained (no SDK import needed)
HStack(spacing: 12) {
Image(systemName: "location.fill").foregroundColor(.blue)
VStack(alignment: .leading) {
Text(context.attributes.title).font(.headline)
Text(context.state.status).font(.subheadline).foregroundColor(.secondary)
}
Spacer()
}
.padding()
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
Text("Tracking")
}
DynamicIslandExpandedRegion(.trailing) {
Text("Live")
}
DynamicIslandExpandedRegion(.bottom) {
Text(context.state.status)
}
} compactLeading: {
Image(systemName: "location.fill").foregroundColor(.blue)
} compactTrailing: {
Text("Live")
} minimal: {
Image(systemName: "location.fill").foregroundColor(.blue)
}
}
}
}यह स्विफ्टयूआई दृश्य अनुकूलित करने के लिए पूरी तरह से आपका है - ActivityConfiguration ब्लॉक के अंदर इसे अपनी पसंद के अनुसार स्टाइल करें, context.attributes.title और context.state.status से डेटा मैप करें।
विजेट एक्सटेंशन के परिनियोजन लक्ष्य को iOS 16.2 पर सेट करें। Xcode का “विजेट एक्सटेंशन” टेम्पलेट अक्सर कंट्रोल विजेट और @main WidgetBundle पर एक @available(iOS 18.0, *) एनोटेशन जोड़ता है। यदि वह एनोटेशन एक्सटेंशन के परिनियोजन लक्ष्य से अधिक है, तो विजेट बंडल (और इसलिए आपकी लाइव गतिविधि) चुपचाप पंजीकृत होने में विफल रहता है - सिस्टम Activity had no descriptor लॉग करता है - और एक्सटेंशन पुराने ओएस संस्करणों पर क्रैश हो सकता है। @main बंडल को एक्सटेंशन के परिनियोजन तल पर उपलब्ध रखें, और किसी भी iOS-18-केवल विजेट (जैसे नियंत्रण विजेट) को if #available(iOS 18.0, *) में लपेटें।
परिदृश्य 6: समाप्त अवस्था (ऐप फोर्स-क्विट)
अवधारणाओं की खोज: ऐप जीवनचक्र, फ़ोर्स-क्विट बनाम ओएस सस्पेंशन
समस्या
आपका उपयोगकर्ता ऐप स्विचर से ऊपर की ओर स्वाइप करता है और ऐप को पूरी तरह से बंद कर देता है। आप उम्मीद करते हैं कि ट्रैसलेट उन्हें पृष्ठभूमि में ट्रैक करना जारी रखेगा, लेकिन स्थान आना बंद हो जाते हैं।
Apple इसे कैसे संभालता है
एंड्रॉइड के विपरीत, जहां एक फ़ोरग्राउंड सेवा अक्सर स्वाइप-टू-डिसमिस से बच सकती है, आईओएस उपयोगकर्ता के इरादे को सख्ती से लागू करता है।
Apple के आधिकारिक कोरलोकेशन दस्तावेज़ीकरण के अनुसार:
“यदि उपयोगकर्ता आपके ऐप को बलपूर्वक छोड़ देता है, तो नए स्थान ईवेंट आने पर सिस्टम स्वचालित रूप से इसे लॉन्च नहीं करता है। सिस्टम द्वारा स्थान ईवेंट वितरित करना शुरू करने से पहले उपयोगकर्ता को स्पष्ट रूप से आपके ऐप को फिर से लॉन्च करना होगा।”
जब कोई उपयोगकर्ता मैन्युअल रूप से ऐप को बलपूर्वक छोड़ देता है:
- मानक स्थान अपडेट: पूरी तरह से बंद।
- महत्वपूर्ण स्थान परिवर्तन (एसएलसी): पूरी तरह से बंद।
- क्षेत्र निगरानी (जियोफेंस): पूरी तरह से बंद।
क्या यह समाप्त स्थिति में काम करेगा?
- यदि ओएस ने ऐप को बंद कर दिया है (उदाहरण के लिए, पृष्ठभूमि में मेमोरी दबाव के कारण): हाँ। जब कोई स्थान घटना घटित होती है (जैसे कोई महत्वपूर्ण परिवर्तन या जियोफ़ेंस ट्रिगर) तो Apple स्वचालित रूप से आपके ऐप को पृष्ठभूमि में पुनः लॉन्च कर देगा। ट्रैसलेट का मूल रस्ट कोर जाग जाएगा और इसे निर्बाध रूप से संभाल लेगा।
- यदि उपयोगकर्ता स्पष्ट रूप से ऐप को बलपूर्वक छोड़ देता है: नहीं। ऐप तब तक मृत रहेगा जब तक उपयोगकर्ता ऐप आइकन को दोबारा खोलने के लिए मैन्युअल रूप से टैप नहीं करता।
ट्रेसलेट इसे कैसे हल करता है
ट्रैसलेट Apple की मूलभूत OS बाधाओं को दरकिनार नहीं कर सकता। हालाँकि, ट्रैसलेट यह सुनिश्चित करता है कि:
- ऐप बंद होने से पहले *सभी अनसिंक किए गए स्थान रस्ट SQLite डेटाबेस में सुरक्षित रूप से बने रहते हैं।
- जैसे ही उपयोगकर्ता ऐप को दोबारा खोलता है, ट्रैसलेट तुरंत ट्रैकिंग शुरू कर देता है और बिना कोई चूक किए किसी भी ऑफ़लाइन डेटा को सिंक कर देता है।