我就是我,不一样的烟火。

iOS为了让设备尽量省电,减少不必要的开销,保持系统流畅,因而对后台机制采用墓碑式的“假后台”。除了系统官方极少数程序可以真后台,一般开发者开发出来的应用程序后台受到以下限制:1.用户按Home之后,App转入后台进行运行,此时拥有180s后台时间(iOS7)或者600s(iOS6)运行时间可以处理后台操作2.当180S或者600S时间过去之后,可以告知系统未完成任务,需要申请继续完成,系统批准申请之后,可以继续运行,但总时间不会超过10分钟。3.当10分钟时间到之后,无论怎么向系统申请继续后台,系统会强制挂起App,挂起所有后台操作、线程,直到用户再次点击App之后才会继续运行。

当然iOS为了特殊应用也保留了一些可以实现“真后台”的方法,摘取比较常用的:1.VOIP2.定位服务3.后台下载4.在后台一直播放无声音乐(容易受到电话或者其他程序影响,所以暂未考虑)5….更多其中VOIP需要绑定一个Socket链接并申明给系统,系统将会在后台接管这个连接,一旦远端数据过来,你的App将会被唤醒10s(或者更少)的时间来处理数据,超过时间或者处理完毕,程序继续休眠。后台现在是iOS7引入的新API,网上实现的代码比较少,博主也没有细心去找。由于博主要做的App需要在后台一直运行,每隔一段时间给服务器主动发送消息来保持帐号登陆状态,因而必须确保App不被系统墓碑限制。博主最先尝试了很多方法,包括朋友发来的一个Demo,每180s后台时间过期就销毁自己然后再创建一个后台任务,但是实际测试只有10分钟时间。最后因为考虑到VOIP对服务端改动太大,时间又太紧,所以选择了定位服务的方法来保持后台。

要启动定位服务:1.需要引入头文件:#import <CoreLocation/CoreLocation.h>2.在AppDelegate.m中定义CLLocationManager * locationManager;作为全局变量方便控制3.在程序启动初期对定位服务进行初始化:

1

2

locationManager = [[CLLocationManager alloc] init];

locationManager.delegate =self;//or whatever class you have for managing location</pre>

4.在程序转入后台的时候,启动定位服务[locationManager startUpdatingLocation];(第一次运行这个方法的时候,如果之前用户没有使用过App,则会弹出是否允许位置服务,关于用户是否允许,后面代码中有判断)这样在定位服务可用的时候,程序会不断刷新后台时间,实际测试,发现后台180s时间不断被刷新,达到长久后台的目的。

但是这样使用也有一些问题,在部分机器上面,定位服务即使打开也可能不能刷新后台时间,,需要完全结束程序再运行。稳定性不知道是因为代码原因还是系统某些机制原因。

下面贴上代码:注意:代码中包含朋友给的demo中,180s时间后销毁自己再创建自己的后台方法,我自己实现过程中加入了定位服务来确保后台能够一直在线。源码参考部分来自网上,因为翻了Google,找了很多英文方面的博文,在此感谢原作者分享。

判断用户是否打开了定位服务,是否禁用了该程序的定位权限:

1

2

3

4

5

if(![CLLocationManager locationServicesEnabled] || ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied))//判断定位服务是否打开

{

[InterfaceFuncation ShowAlertWithMessage:@"错误"AlertMessage:@"定位服务未打开\n保持在线需要后台定位服务\n请到 设置-隐私 中打开定位服务"ButtonTitle:@"我错了"];

return;

}

AppDelegate.m源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

@property(assign, nonatomic) UIBackgroundTaskIdentifier bgTask;

@property(strong, nonatomic) dispatch_block_t expirationHandler;

@property(assign, nonatomic)BOOL jobExpired;

@property(assign, nonatomic)BOOL background;

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

{

UIApplication* app = [UIApplication sharedApplication];

__weakNSUAAAIOSAppDelegate* selfRef =self;

self.expirationHandler = ^{//创建后台自唤醒,当180s时间结束的时候系统会调用这里面的方法

[app endBackgroundTask:selfRef.bgTask];

selfRef.bgTask = UIBackgroundTaskInvalid;

selfRef.bgTask = [app beginBackgroundTaskWithExpirationHandler:selfRef.expirationHandler];

NSLog(@"Expired");

selfRef.jobExpired =YES;

while(selfRef.jobExpired)

{

// spin while we wait for the task to actually end.

NSLog(@"等待180s循环进程的结束");

[NSThreadsleepForTimeInterval:1];

}

// Restart the background task so we can run forever.

[selfRef startBackgroundTask];

};

// Assume that we’re in background at first since we get no notification from device that we’re in background when

// app launches immediately into background (i.e. when powering on the device or when the app is killed and restarted)

[selfmonitorBatteryStateInBackground];

locationManager = [[CLLocationManager alloc] init];

locationManager.delegate =self;

//[locationManager startUpdatingLocation];

returnYES;

}

– (void)monitorBatteryStateInBackground

{

self.background =YES;

[selfstartBackgroundTask];

}

– (void)applicationDidBecomeActive:(UIApplication *)application

{

// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

NSLog(@"App is active");

[UIApplication sharedApplication].applicationIconBadgeNumber=0;//取消应用程序通知脚标

[locationManager stopUpdatingLocation];

self.background =NO;

}

– (void)applicationDidEnterBackground:(UIApplication *)application

{

看着它或是汹涌或是平静,然而一直相随,不离不弃。

我就是我,不一样的烟火。

相关文章:

你感兴趣的文章:

标签云: