2011-05-13 7 views
20

मेरी ऐप आवश्यकता: मुझे कुछ कारणों से पुश अधिसूचना (एपीएन) का उपयोग किये बिना सर्वर पुश पर स्थानीय अधिसूचना को ट्रिगर करने के लिए सॉकेट कनेक्शन बनाए रखना चाहिए। इसलिए मैं सॉकेट कनेक्शन को बनाए रखने के लिए आईफोन की वीओआईपी पृष्ठभूमि क्षमता का उपयोग कर रहा हूं।पृष्ठभूमि में वीओआईपी सॉकेट कनेक्शन कैसे बनाए रखें?

1. पृष्ठभूमि में चलाने के लिए सॉकेट कनेक्शन को जारी रखने के लिए मैंने वीओआईपी के लिए एक स्ट्रीम कॉन्फ़िगर किया है, तो टाइमआउट मान को सेट करना चाहिए? टाइमआउट समाप्त होने के बाद सॉकेट कनेक्शन समाप्त हो जाएगा? मैं अपने आवेदन को हर समय सॉकेट सुनने के लिए कैसे बना सकता हूं।

[[UIApplication sharedApplication] setKeepAliveTimeout:86400 handler:^(void) 
{ 

    if (inputStream) 
     [inputStream close]; 
    if (outputStream) 
     [outputStream close]; 


    urlStr = @"http://192.168.0.108"; 
    website = [NSURL URLWithString:urlStr]; 
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream); 
    CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); 
    CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);  
    inputStream = (NSInputStream *)readStream; 
    outputStream = (NSOutputStream *)writeStream; 
    [inputStream setDelegate:self]; 
    [inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
    [outputStream setDelegate:self]; 
    [outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [inputStream open]; 
    [outputStream open]; 

    }]; 

3. अपने सर्वर पुन: प्रारंभ और एप्लिकेशन कहते हैं:

ग्राहक धारा विन्यास इस प्रकार

NSString *urlStr = @"http://192.168.0.108"; 
NSURL *website = [NSURL URLWithString:urlStr]; 
CFReadStreamRef readStream; 
CFWriteStreamRef writeStream; 
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream); 

CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); 
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);  

NSInputStream *inputStream = (NSInputStream *)readStream; 
NSOutputStream *outputStream = (NSOutputStream *)writeStream; 
[inputStream setDelegate:self]; 
[inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
[outputStream setDelegate:self]; 
[outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; 
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
[inputStream open]; 
[outputStream open]; 

2. मैं हैंडलर applicationDidEnterBackground में धारा फिर से कनेक्ट करना चाहिए है, पृष्ठभूमि में है, मैं कनेक्शन कैसे सुनिश्चित करूं? यदि मेरे आईफोन में वाई-फाई कनेक्शन या यदि मैं सर्वर ऐप को समाप्त करता हूं तो कनेक्शन बंद हो जाएगा, तो मेरे ऐप को उम्मीद के अनुसार काम करने के लिए मुझे क्या उपाय करना चाहिए?

+1

कोड जो आपने यहां शामिल किया है, क्या यह कार्य कोड है? –

उत्तर

19

आपको यह भी सुनिश्चित करने के लिए आप अपने plist फ़ाइल

<key>UIBackgroundModes</key> 
<array> 
    <string>voip</string> 
</array> 

सॉकेट आईओएस द्वारा प्रबंधित किया जाएगा, जबकि अपने आवेदन के पृष्ठभूमि में होने में निर्धारित किया है कि जरूरत है। सॉकेट में उपलब्ध डेटा जल्द ही आपके एप्लिकेशन को CPU समय प्राप्त होगा। तो runLoop में मैं हिंदुस्तान टाइम्स

मेरे मामले संकेतन प्रोटोकॉल एक अलग थ्रेड में काम कर रहा है में जाँच कर रहा हूँ, इसलिए मैं runLoop मेरी आत्म

// Start runloop 
    while (!m_needStop) 
    { 
    CFRunLoopRun(); 
    } 

कताई कर रहा हूँ और यह रोक जब जरूरत:

m_needStop = true; 
    { 
    QAutoLock l(m_runLoopGuard); 
    if (m_runLoop != NULL) 
     CFRunLoopStop(m_runLoop); 
    } 

runLoop में सॉकेट के लिए मैं उन्हें runLoop में समय निर्धारण से पहले सेटअप हैंडलर कार्यों:

int nFlags = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; 
    CFStreamClientContext context; 
    context.info = this; 
    context.version = 0; 
    context.release = NULL; 
    context.retain = NULL; 
    context.copyDescription = NULL; 

    if (!CFReadStreamSetClient(m_readStream, nFlags, NotificationProtocolHandler::ReadStreamCallback, &context)) 
    { 
    ReleaseStreams(); 
    return false; 
    } 

    if (!CFWriteStreamSetClient(m_writeStream, nFlags, NotificationProtocolHandler::WriteStreamCallback, &context)) 
    { 
    ReleaseStreams(); 
    return false; 
    } 

इन कार्यों जो कहा जाएगा जब अपने सॉकेट इच्छा आप के लिए और भले ही कुछ जानकारी है कर रहे हैं पृष्ठभूमि में अपने आवेदन:

void NotificationProtocolHandler::ReadStreamCallback(CFReadStreamRef stream, 
                CFStreamEventType eventType, 
                void *clientCallBackInfo) 
{  
    NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo; 
    switch (eventType) 
    { 
    case kCFStreamEventOpenCompleted: 
     break; 

    case kCFStreamEventHasBytesAvailable: 
     handler->ProcessInput(); 
     break; 

    case kCFStreamEventErrorOccurred: 
     handler->ProcessConnectionError(); 
     break; 

    case kCFStreamEventEndEncountered: 
     handler->ProcessConnectionError(); 
     break; 

    default: 
     break; // do nothing 
    } 
} 

void NotificationProtocolHandler::WriteStreamCallback(CFWriteStreamRef stream, 
                 CFStreamEventType eventType, 
                 void *clientCallBackInfo) 
{ 
    NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo; 

    switch (eventType) 
    { 
    case kCFStreamEventOpenCompleted: 
     handler->ProcessOutputConnect(); 
     break; 

    case kCFStreamEventCanAcceptBytes: 
     handler->ProcessReadyToWrite(); 
     break; 

    case kCFStreamEventErrorOccurred: 
     handler->ProcessConnectionError(); 
     break; 

    case kCFStreamEventEndEncountered: 
     handler->ProcessConnectionError(); 
     break;  

    default: 
     break; // do nothing 
    } 
} 

सर्वर पता है कि ग्राहक अभी भी जीवित है हम करने के लिए पिंग कमांड भेजने बनाने के प्रत्येक 10 मिनट में सर्वर ताकि KeepAlive हैंडलर 600 पर सेट हो। आप बैटरी को बचाने के लिए अन्य मानों का उपयोग कर सकते हैं लेकिन यह क्लाइंट और सर्वर पक्ष पर डिस्कनेक्ट की पहचान को और खराब कर देगा। और डिस्कनेक्ट और रीकनेक्ट के बीच का समय बढ़ाएगा।

BOOL scheduled = [app setKeepAliveTimeout:pingTimeout handler:^{ // Schedule processing after some time interval  

    SchedulePing(0); 
} 

कहाँ SchedulePing (0) निम्नलिखित के रूप में क्रियान्वित की जाएगी:

StartLongBGTask(); 
if (avoidFinishBgTask != NULL) 
    *avoidFinishBgTask = true; 
m_pingTimer = CreateTimer(pingTimeout, PingTimerCallback); // result is ignored 

और StartLongBGTask है एक

m_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{ 
    [[UIApplication sharedApplication] endBackgroundTask:m_bgTask]; 
    m_bgTask = UIBackgroundTaskInvalid; 
}]; 

यह सुनिश्चित करें कि आवेदन भेजने से पहले निलंबित नहीं किया जाएगा बनाने के लिए आवश्यक है पिंग और सर्वर से पिंग पर जवाब का इंतजार कर रहा है। अगर सॉकेट पहले ही डिस्कनेक्ट हो गया है तो यह हो सकता है कि रीकनेक्ट की आवश्यकता हो, जिसमें कुछ समय लगेगा और पृष्ठभूमि में चलने के लिए प्रोसेस की आवश्यकता होगी।

लेकिन जब आपको अब उनकी आवश्यकता नहीं होती है तो पृष्ठभूमि कार्यों को ठीक से मुक्त करना सुनिश्चित करें। बीजी टाइमआउट पार होने पर सिस्टम द्वारा अन्य बुद्धिमान आवेदन मारे जाएंगे।

+0

बस एक पोस्ट पर ठोकर खाई, जिसमें कहा गया था कि एक ऐप खारिज कर दिया गया था क्योंकि उसने वॉयस ओवर आईपी सेवाओं को प्रदान नहीं किया था, लेकिन वीओआईपी पृष्ठभूमि मोड का इस्तेमाल किया था। इस बारे में कोई विचार है? तो अगर मैं एक आईएम ऐप विकसित कर रहा हूं और मैं चाहता हूं कि सॉकेट पृष्ठभूमि में भी जीवित रहे, तो क्या मैं इस उपर्युक्त दृष्टिकोण का उपयोग कर सकता हूं, भले ही मैं किसी भी आवाज क्षमताओं का समर्थन नहीं करूँगा? – Roshit

+0

क्या आपको अपना ऐप स्वीकृत कर दिया गया था?- मैं एक समान स्थिति में हूं लेकिन सौभाग्य से मैं एंटरप्राइज़ वितरण का उपयोग कर सकता हूं वैसे भी – gheese

+0

इसके बारे में भी उत्सुक है। अगर आपके पास कुछ कहानियां हैं तो कृपया झुक जाओ! – Nailer

2

एप्पल यहाँ https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/AdvancedAppTricks/AdvancedAppTricks.html

प्रलेखन के अनुसार इसे पा सकते हैं आधिकारिक documentation.You पर इस बारे में विवरण प्रदान की है

एक वीओआईपी एप्लिकेशन को लागू करने के लिए कई शर्तें हैं:

1. अपने ऐप की Info.plist फ़ाइल में UIBackgroundModes कुंजी जोड़ें। इस कुंजी का मान उस सरणी में सेट करें जिसमें वीओआईपी स्ट्रिंग शामिल है।

2. वीओआईपी उपयोग के लिए ऐप के सॉकेट में से एक को कॉन्फ़िगर करें।

3. पृष्ठभूमि पर जाने से पहले, सेटकिपअलीवटाइमआउट: हैंडलर: समय-समय पर निष्पादित करने के लिए एक हैंडलर स्थापित करने के लिए विधि को कॉल करें। आपका ऐप इस सेवा कनेक्शन को बनाए रखने के लिए इस हैंडलर का उपयोग कर सकता है।

4. सक्रिय उपयोग से और संक्रमण से संक्रमण को संभालने के लिए अपने ऑडियो सत्र को कॉन्फ़िगर करें।

5. आईफोन पर बेहतर उपयोगकर्ता अनुभव सुनिश्चित करने के लिए, सेल टेलीफ़ोनी फ्रेमवर्क का उपयोग सेल-आधारित फोन कॉल के संबंध में अपने व्यवहार को समायोजित करने के लिए करें; कोर टेलीफोनी फ्रेमवर्क संदर्भ देखें।

6. अपने वीओआईपी ऐप के लिए अच्छा प्रदर्शन सुनिश्चित करने के लिए, नेटवर्क परिवर्तनों का पता लगाने के लिए सिस्टम कॉन्फ़िगरेशन फ्रेमवर्क का उपयोग करें और जितना संभव हो सके अपने ऐप को सोने दें।

UIBackgroundModes कुंजी में वीओआईपी मान सहित सिस्टम को यह पता करने देता है कि इसे ऐप को अपने नेटवर्क सॉकेट को प्रबंधित करने के लिए पृष्ठभूमि में चलाने की अनुमति देनी चाहिए। यह कुंजी आपके ऐप को पृष्ठभूमि ऑडियो चलाने की अनुमति देती है (हालांकि UIBackgroundModes कुंजी के लिए ऑडियो मान सहित अभी भी प्रोत्साहित किया जाता है)। सिस्टम कुंजी के तुरंत बाद पृष्ठभूमि में इस कुंजी के साथ एक ऐप भी पृष्ठभूमि में फिर से लॉन्च किया जाता है ताकि वीओआईपी सेवाएं हमेशा उपलब्ध हों। UIBackgroundModes कुंजी के बारे में अधिक जानकारी के लिए, जानकारी संपत्ति सूची कुंजी संदर्भ देखें।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^