6

Tôi đang đau đầu với chủ đề. Tôi đang làm việc trên một ứng dụng mà cần phải thăm dò ý kiến ​​một máy chủ web thường xuyên, để kiểm tra dữ liệu mới. Dựa trên thông tin được trả lại, tôi muốn gửi thông báo cục bộ cho người dùng.setKeepAliveTimeout và BackgroundTasks

Tôi biết rằng phương pháp này hơi khác so với mô tả được Apple mô tả, trong đó máy chủ từ xa thực hiện công việc, đẩy thông báo từ xa, dựa trên APNS. Tuy nhiên, có nhiều lý do mà tôi không thể xem xét cách tiếp cận này. Một cho tất cả, là cơ chế xác thực người dùng. Máy chủ từ xa, vì lý do bảo mật, không thể tính đến thông tin đăng nhập của người dùng. Tất cả những gì tôi có thể làm là để di chuyển đăng nhập và lấy lõi, cho khách hàng (iPhone).

Tôi nhận thấy rằng Apple cung cấp cơ hội cho các ứng dụng đánh thức và tiếp tục mở kết nối Ổ cắm (ví dụ: ứng dụng VoIP).

Vì vậy, tôi bắt đầu điều tra theo cách này. Thêm thông tin cần thiết trong plist, tôi có thể "đánh thức" ứng dụng của tôi, sử dụng một cái gì đó như thế này trong appdelegate tôi:

[[UIApplication sharedApplication] setKeepAliveTimeout:1200 handler:^{ 
    NSLog(@"startingKeepAliveTimeout"); 
    [self contentViewLog:@"startingKeepAliveTimeout"]; 
    MyPushOperation *op = [[MyPushOperation alloc] initWithNotificationFlag:0 andDataSource:nil]; 
    [queue addOperation:op]; 
    [op release]; 
}]; 

Các NSOperation, sau đó bắt đầu một công việc nền sử dụng mã khối như sau:

#pragma mark SyncRequests 
-(void) main { 
    NSLog(@"startSyncRequest"); 
    [self contentViewLog:@"startSyncRequest"]; 
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
     NSLog(@"exipiration handler triggered"); 
     [app endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
     [self cancel]; 
    }]; 


     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      NSMutableURLRequest *anURLRequest; 
      NSURLResponse *outResponse; 
      NSError *exitError; 
      NSString *username; 
      NSString *password; 

      NSLog(@"FirstLogin"); 
      anURLRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:webserverLogin, username, password]]]; 
      [anURLRequest setHTTPMethod:@"GET"]; 
      [anURLRequest setTimeoutInterval:120.00]; 
      [anURLRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData]; 

      exitError = nil; 
      NSData *tmpData = [NSURLConnection sendSynchronousRequest:anURLRequest returningResponse:&outResponse error:&exitError]; 
      [anURLRequest setTimeoutInterval:120.00]; 
      if(exitError != nil) { //somethings goes wrong 
       NSLog(@"somethings goes wrong"); 
       [app endBackgroundTask:bgTask]; 
       bgTask = UIBackgroundTaskInvalid; 
       [self cancel]; 
       return; 
      } 

      //do some stuff with NSData and prompt the user with a UILocalNotification 

      NSLog(@"AlltasksCompleted"); 
      [app endBackgroundTask:bgTask]; 
      bgTask = UIBackgroundTaskInvalid; 
      [self cancel]; 
     }); 
    } 
} 

Đoạn mã trên dường như làm việc (đôi khi), nhưng nhiều người khác nó bị treo ứng dụng của tôi, với các thông tin đăng nhập sau:

Exception Type: 00000020 
Exception Codes: 0x8badf00d 
Highlighted Thread: 3 

Application Specific Information: 
DemoBackApp[5977] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0xa9da0b0> identifier: UIKitBackgroundCompletionTask process: DemoBackApp[5977] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:5977 preventSuspend preventIdleSleep 
)} 

Elapsed total CPU time (seconds): 0.010 (user 0.010, system 0.000), 100% CPU 
Elapsed application CPU time (seconds): 0.000, 0% CPU 

Đối với những người hỏi, vâng. Tôi cũng đã thử phương pháp Async NSURLConnection. Không vấn đề. Nó sụp đổ như nhau, ngay cả khi tôi sử dụng một cách tiếp cận không đồng bộ với xử lý thời gian chờ và didFinishLoading: WithError.

Tôi bị kẹt. Bất kỳ gợi ý nào đều được đánh giá cao.

Trả lời

7

Khi bạn gọi -setKeepAliveTimeout:handler:, bạn chỉ nhận được tối đa 30 giây để hoàn thành mọi thứ và tạm ngưng. Bạn không được cung cấp cùng một thời hạn gia hạn nền khi bạn được cung cấp khi ứng dụng của bạn được chuyển đổi lần đầu sang nền. Điều đó có nghĩa là để hoàn thành các tác vụ chạy dài, tắt mọi thứ, v.v.

Với cuộc gọi VOIP, bạn chỉ cần gửi bất kỳ gói ping nào bạn cần gửi đến dịch vụ để giữ kết nối mạng luôn hoạt động và không bị hẹn giờ -ngoài. Sau 30 giây, bất kể bắt đầu nhiệm vụ nền mới, nếu ứng dụng của bạn vẫn đang thực thi, bạn sẽ bị chấm dứt.

Ngoài ra, điều quan trọng cần lưu ý là nếu bạn không thực sự là một ứng dụng VOIP hoặc nếu bạn làm bất cứ điều gì trong cửa sổ chính thức callback mà không liên quan đến việc giữ kết nối mạng của bạn mở, ứng dụng của bạn sẽ được bị từ chối từ cửa hàng ứng dụng. Khi bạn đặt bất kỳ cờ hoạt động nào (VOIP, nhạc nền, điều hướng), họ sẽ kiểm tra nó một cách nghiêm ngặt để đảm bảo rằng nó chỉ chỉ làm những gì được gắn cờ để làm trong khi ở chế độ nền. Thực hiện bất kỳ loại yêu cầu HTTP GET nào và chờ một số cập nhật dữ liệu lớn quay lại gần như chắc chắn sẽ khiến ứng dụng của bạn bị từ chối.

CHỈNH SỬA: Như được chú thích của Patrick trong các nhận xét, khoảng thời gian hiện tại mà khối được đưa ra để thực thi đã được giảm từ 30 giây xuống còn 10 giây với iOS 5.Bạn nên theo dõi những lần này bất cứ khi nào bạn liên kết lại ứng dụng của mình để có phiên bản SDK mới, ít nhất hãy nhanh chóng kiểm tra tài liệu trong trường hợp chúng được cập nhật (với iOS 6 sắp ra mắt, con số này có thể được điều chỉnh lại).

+0

cảm ơn bạn đã trả lời. Trước hết, từ chối không phải là một vấn đề, vì ứng dụng là một ứng dụng riêng tư không dành cho AppStore. Về thời gian chờ 30 giây, tôi đã đọc về nó, nhưng tôi không thể hiểu tại sao nhật ký sự cố cho tôi biết về thời gian chờ 600.00 giây, chứ không phải 30 giây. Hơn nữa, đôi khi các phương pháp hoạt động, những người khác thì không. – valvoline

+0

@valvoline: Thời gian không hoạt động, nhiệm vụ nền của bạn rõ ràng là mất quá nhiều thời gian. Các tài liệu nói 30 giây, nhưng có lẽ đó là số mềm và hệ điều hành thực sự cung cấp cho bạn 10 phút, tôi không chắc chắn. Tuy nhiên, chúng tôi biết rằng có điều gì đó đang bị chặn và không thể hoàn thành, và vì VIOP được thiết kế để kiểm tra nhanh, có thể việc xử lý lỗi từ hệ điều hành bị nhầm lẫn (như không gọi khối hủy của bạn) . –

+0

@ jason: Bạn có bất kỳ chi tiết cụ thể nào về những gì họ yêu cầu trong cửa sổ VOIP này không? Liệu nó nói rằng bất cứ nơi nào công cộng? –

3

Dường như bạn có thể kết hợp trình xử lý thời gian chờ giữ lại bằng cách yêu cầu thực hiện nhiệm vụ nền hữu hạn khi bạn được gọi. Điều này sẽ cho phép bạn một 10 phút đầy đủ mỗi khi VOIP giữ xử lý còn sống được gọi (phó 10-30 giây bình thường).

Vẫn còn vấn đề như trên - bạn cần cờ VOIP để gửi và Apple không thể chấp nhận đơn đăng ký của bạn nếu bạn có cờ đó và không thực sự là ứng dụng VOIP, nhưng cho nội bộ phân phối (doanh nghiệp hoặc cách khác), giải pháp này sẽ làm việc tốt cho bạn thời gian nền.

Trong thử nghiệm của tôi, bộ đếm thời gian thực thi 10 phút được đặt lại mỗi lần trình xử lý VOIP được gọi (cho dù người dùng đã đưa ứng dụng lên phía trước từ đó), và điều này có nghĩa là bạn có thể thăm dò ý kiến ​​máy chủ của mình vô thời hạn trong khi ở chế độ nền sau mỗi 600 giây (10 phút) và quá trình bỏ phiếu có thể mất đến 10 phút trước khi đi ngủ (nghĩa là hoạt động nền gần như không đổi nếu đó là những gì bạn yêu cầu).

Một lần nữa, không thực sự là một tùy chọn cho App Store trừ khi bạn có thể thuyết phục họ rằng bạn là VOIP.

+0

Bạn có đặt lại hẹn giờ thực hiện theo cách thủ công trong trình xử lý ´setKeepAliveTimeout´ của bạn không? Bạn có thể cung cấp một số mã ví dụ cho điều này không? Tôi đang ở trong tình trạng tương tự, bằng cách sử dụng VOIP (sẽ không gửi đến AppStore). Bộ hẹn giờ thực hiện của tôi không được đặt lại tự động khi ứng dụng được thiết lập bởi setKeepAliveTimeout. Dường như tôi có thể đặt lại bằng cách tạo tác vụ nền mới theo cách tương tự như trong ´applicationDidEnterBackground´ của tôi. – reekris

+0

Có, mỗi lần setKeepAliveTimeout được gọi là tôi tạo một tác vụ nền hữu hạn mới (có vẻ như để có được 10 phút chạy mới). – BadPirate

8

Đây là một chuỗi cũ nhưng có thể đảm bảo cập nhật.

Tính đến iOS 6, đây là hành vi tôi nhìn thấy với các phương pháp timer nền VoIP như đã thảo luận trong chủ đề này:

  • Các VoIP BackgroundMode vẫn bị cấm nghiêm ngặt từ các ứng dụng AppStore thông qua quá trình App xét
  • Thời gian KeepAlive tối thiểu là 600 giây; bất cứ điều gì ít hơn sẽ gây ra việc xử lý không được cài đặt (và một cảnh báo được gửi đến NSLog)
  • Đặt thời gian lưu giữ cho một thứ gì đó lớn hơn 600 giây sẽ thường dẫn đến việc xử lý được kích hoạt với tần suất mỗi thời gian/2 khoảng thời gian. Thực tế tiền thưởng: Điều này phù hợp với yêu cầu SIP REGISTER, trong đó khoảng thời gian đăng ký lại được đề xuất là 0,5 * thời gian đăng ký lại.
  • Khi xử lý keepalive của bạn được gọi, tôi đã quan sát như sau:
    • Bạn nhận được khoảng 10 giây của "tiền cảnh" thời gian thực hiện, trong đó thời gian nền còn lại là vô hạn (như trả về bởi backgroundTimeRemaining)
    • Nếu bạn khởi động một beginBackgroundTask từ bên trong handler keepalive, tôi đã quan sát thấy rằng bạn nhận được 60 giây thời gian thi công nền (như trả về bởi backgroundTimeRemaining). Điều này khác với 600 giây bạn nhận được khi người dùng chuyển từ ứng dụng của bạn đang hoạt động sang nền. tôi đã không tìm thấy bất cứ cách nào để kéo dài thời gian này (mà không sử dụng thủ thuật khác như vị trí, vv)

Hy vọng rằng sẽ giúp!

5

Chỉ cần cập nhật hành vi này cho iOS7.

  • Khi ứng dụng của bạn lần đầu tiên chạy vào nền, bạn sẽ nhận được 180 giây thời gian tác vụ là như được báo cáo bởi backgroundTimeRemaining. Tuy nhiên, nó dừng lại phản hồi sau 5 giây trước khi hết thời gian này theo báo cáo của backgroundTimeRemaining.
  • Khi tác vụ keepAlive kích hoạt thì backgroundTimeRemaining là 10 giây tiền cảnh, tiếp theo là 60 giây của đồng hồ nền dưới dạng được báo cáo bởi backgroundTimeRemaining. Nó cũng dừng đáp ứng lúc 5 giây trước khi hết thời gian này như được báo cáo bởi backgroundTimeRemaining.

Vì vậy, trên iOS7, bạn có thể nhận được 65 giây thời gian xử lý cứ sau 10 phút.

Các vấn đề liên quan