IOS background Targeting

Source: Internet
Author: User
<span id="Label3"></p><p><p>Http://www.cocoachina.com/ios/20150724/12735.html</p></p><p><p></p></p><p><p><strong>Objective</strong></p></p><p><p>The previous article said that I'm doing a social app for lbs. one of the main functions is to be able to locate the position of each member in the social circle in real-time background real-time upload location is a very important technical point next, i'll Talk about my practical experience in this Area.</p></p><p><p><strong>Demand</strong></p></p><p><p>Let's take a look at the specific requirements for implementing this feature because we are real-time targeting of life social apps so we need to do a few things</p></p><p><p>1. If the location of the user is constantly changing, escalate it over time</p></p><p><p>Because we want to be able to feedback the User's location changes in real-time in the app, so the timing of the escalation is just needed</p></p><p><p>2. If the User's movement is very slow, it is reported in a distance</p></p><p><p>If the user is in a low-rate state (for example, walking speed is probably about 1m/s) this time if you also press (1) in the way to escalate the point on the map because the changes are too small the points will be very dense this data is not significant (and if you want to do the track service, these dense points must be spent) So at this point we're reporting at distance intervals.</p></p><p><p>3. Do not continue reporting if the User's location has not changed after arriving at a place</p></p><p><p>We only care about the change in location if the User's location is not changed or small changes are not required to report their location (such as entering the company or waiting for a long time of the red light) at this time we do not report (to achieve the purpose of saving Electricity)</p></p><p><p>4. Switch to the backend to be able to locate the escalation</p></p><p><p>Background escalation is a must for users who cannot run our app all the time (iOS4 supported at the Start)</p></p><p><p>5. After the app is terminated for various reasons (the user actively shuts down, the system Kills) also to be able to locate the escalation</p></p><p><p>The chance of users to actively close the app is not very good, but because the system is killed by the situation is very common in this time we also have to be able to report (iOS7 started to support the kill after the Wake)</p></p><p><p>After analyzing the requirements, we will begin to explain how to implement</p></p><p><p><strong>Get ready</strong></p></p><p><p>First do some preparatory work</p></p><p><p>Open background Modes in Target's capabilities option and tick location updates</p></p><p><p></p></p><p><p>Then add the Nslocationalawaysusagedescription key in the plist to type anything in value</p></p><p><p></p></p><p><p>Complete these two steps of our pre-work completed the Background modes is a new feature iOS7 brought in and nslocationalawaysusagedescription in order to enhance the introduction of the mechanism of the prompt description does not add this word location function but can not be used</p></p><p><p><strong>Code</strong></p></p><p><p>Positioning must deal with cllocationmanager. so let's define a subclass of Cllocationmanager and define three variables based on the points in the Requirements.</p></p> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td class="gutter">123456</td> <td class="code"><code class="js plain">@interface MMLocationManager : CLLocationManager</code><code class="js plain">+ (instancetype)sharedManager;</code><code class="js plain">@property (nonatomic, assign) CGFloat minSpeed;     </code><code class="js comments">//最小速度</code><code class="js plain">@property (nonatomic, assign) CGFloat minFilter;    </code><code class="js comments">//最小范围</code><code class="js plain">@property (nonatomic, assign) CGFloat minInteval;   </code><code class="js comments">//更新间隔</code><code class="js plain">@end</code></td> </tr> </tbody> </table><p><p>Here's a few arguments to explain</p></p> <ul class=" list-paddingleft-2"> <ul class=" list-paddingleft-2"> <li><p>Minspeed if the current speed of movement is greater than this value (1) is updated based on time (minfilter) if the current motion speed is less than this value to meet the demand (2) to the extent of the update basis (mininteval)</p></li> <li><p>Minfilter minimum trigger range for demand (1)</p></li> <li><p>Mininteval update interval for demand (2)</p></li> </ul> </ul><p><p>Next is the initialization function</p></p> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td class="gutter">1234567891011121314</td> <td class="code"><code class="js plain"><code class="js plain">- (instancetype)init</code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">self = [</code></code><code class="js keyword"><code class="js keyword">super</code></code><code class="js plain"><code class="js plain">init];</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js keyword"><code class="js keyword">if</code></code><code class="js plain"><code class="js plain">( self )</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">self.minSpeed = 3;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">self.minFilter = 50;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">self.minInteval = 10;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">self.delegate = self;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">self.distanceFilter  = self.minFilter;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">self.desiredAccuracy = kCLLocationAccuracyBest;</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">}</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js keyword"><code class="js keyword">return</code></code><code class="js plain"><code class="js plain">self;</code></code><code class="js plain"><code class="js plain">}</code></code></td> </tr> </tbody> </table><p><p>The default values here can be adjusted to suit your NEEDS.</p></p><p><p>And then the post-update processing logic is actually pretty simple.</p></p> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td class="gutter">123456789</td> <td class="code"><code class="js plain">-  (void) locationmanager: (cllocationmanager *) manager  Didupdatelocations: (nsarray *) Locations </code> <code class="js plain">{</code> <code class="js spaces">      </code> <code class="js plain">cllocation *location = locations[0]; </code> <code class="js spaces">     </code> <code class="js plain">nslog (@ </code> <code class="js string" "%@" < code> <code class="js plain">,location); </code> <code class="js spaces">     </code> <code class="js comments">//adjust the trigger range according to the actual situation </code> <code class="js spaces">     </code> <code class="js plain">[self adjustdistancefilter:location]; </code> <code class="js spaces">     </code> <code class="js comments">//upload data </code> <code class="js spaces">     </code> <code class="js plain">[self uploadlocation:location]; </code> <code class="js plain"> </code> </code></td> </tr> </tbody> </table><p><p>And this adjustdistancefilter function is the core of the entire code will be based on the current speed to dynamically adjust distancefilter This parameter to meet our needs</p></p> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td class="gutter">123456789101112131415161718192021222324252627282930</td> <td class="code"><code class="js comments"><code class="js comments">/**</code></code><code class="js comments"><code class="js comments">*  规则: 如果速度小于minSpeed m/s 则把触发范围设定为50m</code></code><code class="js comments"><code class="js comments">*  否则将触发范围设定为minSpeed*minInteval</code></code><code class="js comments"><code class="js comments">*  此时若速度变化超过10% 则更新当前的触发范围(这里限制是因为不能不停的设置distanceFilter,</code></code><code class="js comments"><code class="js comments">*  否则uploadLocation会不停被触发)</code></code><code class="js comments"><code class="js comments">*/</code></code><code class="js plain"><code class="js plain">- (void)adjustDistanceFilter:(CLLocation*)location</code></code><code class="js plain"><code class="js plain">{</code></code><code class="js comments"><code class="js comments">//    NSLog(@"adjust:%f",location.speed);</code></code><code class="js spaces"><code class="js spaces">    </code></code> <code class="js spaces"><code class="js spaces">    </code></code><code class="js keyword"><code class="js keyword">if</code></code><code class="js plain"><code class="js plain">( location.speed < self.minSpeed )</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js keyword"><code class="js keyword">if</code></code><code class="js plain"><code class="js plain">( fabs(self.distanceFilter-self.minFilter) > 0.1f )</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">            </code></code><code class="js plain"><code class="js plain">self.distanceFilter = self.minFilter;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">}</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">}</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js keyword"><code class="js keyword">else</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">CGFloat lastSpeed = self.distanceFilter/self.minInteval;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js keyword"><code class="js keyword">if</code></code> <code class="js plain"><code class="js plain">( (fabs(lastSpeed-location.speed)/lastSpeed > 0.1f) || (lastSpeed < 0) )</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">            </code></code><code class="js plain"><code class="js plain">CGFloat newSpeed  = (int)(location.speed+0.5f);</code></code><code class="js spaces"><code class="js spaces">            </code></code><code class="js plain"><code class="js plain">CGFloat newFilter = newSpeed*self.minInteval;</code></code><code class="js spaces"><code class="js spaces">            </code></code><code class="js spaces"><code class="js spaces">            </code></code><code class="js plain"><code class="js plain">self.distanceFilter = newFilter;</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">}</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">}</code></code><code class="js plain"><code class="js plain">}</code></code></td> </tr> </tbody> </table><p><p>It is important to note that the Distancefilter parameter cannot be set all the time because the didupdatelocations callback will be triggered immediately after the next second after each setup (the Standard Minimum update interval for the system is 1 seconds and the update frequency is 1hz) So it only resets when the change is over 10% distancefilter</p></p><p><p>And then we're going to do the last step in order to be awakened correctly in the case of being killed. add the following code to the Appdelegate didfinishlaunchingwithoptions</p></p> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td class="gutter">12345678910111213</td> <td class="code"><code class="js keyword"><code class="js keyword">if</code></code><code class="js plain"><code class="js plain">([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {</code></code><code class="js spaces"><code class="js spaces">    </code></code> <code class="js spaces"><code class="js spaces">    </code></code><code class="js keyword"><code class="js keyword">if</code></code><code class="js plain"><code class="js plain">( [[MMLocationManager sharedManager] respondsToSelector:@selector(requestAlwaysAuthorization)] )</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">[[MMLocationManager sharedManager] requestAlwaysAuthorization];</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">}</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js comments"><code class="js comments">//这是iOS9中针对后台定位推出的新属性 不设置的话 可是会出现顶部蓝条的哦(类似热点连接)</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js keyword"><code class="js keyword">if</code></code><code class="js plain"><code class="js plain">( [self respondsToSelector:@selector(allowsBackgroundLocationUpdates)])</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">{</code></code><code class="js spaces"><code class="js spaces">        </code></code><code class="js plain"><code class="js plain">[MMLocationManager sharedManager].allowsBackgroundLocationUpdates = YES;</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">}</code></code><code class="js spaces"><code class="js spaces">    </code></code><code class="js plain"><code class="js plain">[[MMLocationManager sharedManager] startUpdatingLocation];</code></code><code class="js plain"><code class="js plain">}</code></code></td> </tr> </tbody> </table><p><p>This is because the app that was killed in the background is woken up by the system launchoptions will contain the uiapplicationlaunchoptionslocationkey** field to identify it then we can restart the positioning function</p></p><p><p>The positioning function that satisfies our needs is completed so I wrote a demo to verify (using the simulator and selecting Debug->location->freeway Drive) the results are as follows</p></p><p><p></p></p><p><p></p></p><p><p>And then we'll talk about a couple of questions.</p></p><p><p><strong>Discuss</strong></p></p><p><p><strong>Why not use a timer to control the positioning interval</strong></p></p><p><p>There are many tutorials on the web that are implemented with nstimer, but this is not very good though the location of the interval is fixed but the problem of power consumption cannot be solved the background will continue to update the location regardless of whether the current location is updated of course, if your use of the scene is to be uploaded every time you can use the timer to handle</p></p><p><p><strong>There are some problems with distancefilter.</strong></p></p><p><p>Because the time interval of Distancefilter=currentspeed*mininteval is fluctuating due to the change of speed, but the fluctuation is in an acceptable range if the speed is faster or slower then the next update time will be shortened or extended accordingly But because we're in real life, the speed changes can't be so fast, so this error is acceptable, and we're going to be able to distancefilter the speed, and the overall interval will remain within our Range.</p></p><p><p><strong>Why not use Allowdeferredlocationupdatesuntiltraveled:timeout:</strong></p></p><p><p>Allowdeferredlocationupdatesuntiltraveled is a new API introduced by IOS6 look at the name we can know that the function is to delay the position update until the move xx meters or time over xx seconds So this function doesn't exactly meet all of our requirements? But it never occurred to me that this function is not useful</p></p><p><p>And then the time for the spit? (????)</p></p><p><p>Why does this function not work? First of all, This function requires a lot of us to see what it takes to get this function to Work.</p></p> <ul class=" list-paddingleft-2"> <ul class=" list-paddingleft-2"> <li><p>Must be iPhone5 and after the hardware device is supported</p></li> <li><p>Desiredaccuracy must be set to Kcllocationaccuracybest or kcllocationaccuracybestfornavigation</p></li> <li><p>Distancefilter must be set to Kcldistancefilternone</p></li> <li><p>The foreground runtime is not deferred until the app is running in the background</p></li> <li><p>Only when the system is low power state is it possible to take effect</p></li> </ul> </ul><p><p>About the description of low Power state in iOS I only found part of the definition in the documentation on the Apple Website.</p></p><p><p>IOS is very good at getting a device to a low power state when it's not being Used. At idle, very little power are drawn and energy impact are LOW. When tasks is actively occurring, system resources is being used and those resources require ENERGY. however, sporadic tasks can cause the device to enter an intermediate state-neither idle nor active-when the device isn ' t Doing anything. There may is enough time during these intermediate states for the device to reach absolute idle before the next task E Xecutes. When this occurs, energy is wasted and the user ' s battery drains faster.</p></p><p><p>As far as I can see, this **low Power state "is only possible to trigger the operation of any battery screen (not just the lock screen) in a black screen (even if the push is Counted) will cause the app to exit this state at the same time if it is not accessible in the charging State.</p></p><p><p>I try to use this API on the real machine and simulator but the result app is still positioned at 1HZ (the reason for Kcldistancefilternone is Set)</p></p><p><p>Although locationmanager:didfinishdeferredupdateswitherror: a successful callback after the specified time, but the result is not deffer so I checked the original function cannot be debugged directly because:</p></p> <ul class=" list-paddingleft-2"> <ul class=" list-paddingleft-2"> <li><p>Emulator deferredlocationupdatesavailable is not supported to detect if the device supports the emulator to return no</p></li> <li><p>True-machine debugging is not supported because Xcode prevents program hibernation when debugging causes the program to fail to enter a low-power state</p></li> </ul> </ul><p><p>The conclusion is that ... This thing can't even debug, so I don't have that much time to run outside to test this stuff ... moreover, the use of my above method has basically been able to meet the demand ... So i've given up on this API because even using this thing is just icing on the cake.</p></p><p><p>If there are students who know how to use this thing correctly please leave a message to tell me thank you!</p></p><p><p><strong>Summary</strong></p></p><p><p>The demo can be found here in addition to the demo used in the realm to store data (analog upload Operation) interested students can see</p></p><p><p>IOS background Targeting</p></p></span>
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.