2012-09-14 38 views
6

मैं ऐसे ऐप पर काम कर रहा हूं जहां वैश्विक कुंजी-डाउन ईवेंट का उपयोग करना इसके संचालन के लिए एक आवश्यकता होगी। इसके अतिरिक्त, मैं ऐप स्टोर के माध्यम से इसे सख्ती से वितरित करने की योजना बना रहा हूं। (यह एक मैक ऐप है, आईओएस नहीं।) मुझे addGlobalMonitorForEventsMatchingMask के माध्यम से काम कर रहे वैश्विक कार्यक्रमों को सुनने का एक उदाहरण मिला है, लेकिन चेतावनी के साथ।वैश्विक घटनाएं, मैक ऐप स्टोर, और सैंडबॉक्स

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

सिद्धांत मुद्दा यह है कि वैश्विक घटनाओं का पता लगाने के लिए ऐप को भरोसा किया जाना चाहिए। अन्यथा, सभी ऐप्स के लिए अभिगम्यता सक्षम होना आवश्यक है। जब मैं अभिगम्यता को सक्षम करता हूं, तो ईवेंट सफलतापूर्वक पता चला है। यह आवश्यकता यहां दस्तावेज है, http://developer.apple.com/library/mac/#DOCUMENTATION/Cocoa/Conceptual/EventOverview/MonitoringEvents/MonitoringEvents.html

मैं इसे अपने उपयोगकर्ताओं के लिए पसंद करूंगा, उन्हें पहुंच क्षमता को सक्षम नहीं करना होगा। मैंने किए गए अन्य शोधों से, आप AXMakeProcessTrusted को कॉल करके विश्वसनीय होने के लिए एप्लिकेशन प्राप्त कर सकते हैं, फिर एप्लिकेशन को पुनरारंभ करना।

मैं जिस कोड का उपयोग कर रहा हूं, मुझे प्रमाणीकरण प्रॉम्प्ट नहीं मिलता है। ऐप पुनरारंभ होगा, लेकिन अभी भी भरोसा नहीं है (संभवतः क्योंकि मुझे प्रमाणीकरण प्रॉम्प्ट नहीं मिलता है)।

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 

    if (!AXAPIEnabled() && !AXIsProcessTrusted()) { 

     NSString *appPath = [[NSBundle mainBundle] bundlePath]; 
     AXError error = AXMakeProcessTrusted((CFStringRef)CFBridgingRetain(appPath)); 

     [self restartApp]; 
    } 
} 

- (void)restartApp{ 

    NSTask *task = [[NSTask alloc] init]; 
    NSMutableArray *args = [NSMutableArray array]; 
    [args addObject:@"-c"]; 
    [args addObject:[NSString stringWithFormat:@"sleep %d; open \"%@\"", 3, [[NSBundle mainBundle] bundlePath]]]; 
    [task setLaunchPath:@"/bin/sh"]; 
    [task setArguments:args]; 
    [task launch]; 
    [NSApp terminate:nil]; 

} 

इसके अलावा, मैं प्राधिकरण सेवा कार्य यहां https://developer.apple.com/library/mac/#documentation/security/conceptual/authorization_concepts/03authtasks/authtasks.html#//apple_ref/doc/uid/TP30000995-CH206-BCIGAIAG के लिए दस्तावेज़ देखा है: यहाँ इस हिस्से के लिए अपने कोड है।

पहली बात जो मुझे चिंतित करती है, वह इस जानकारी बॉक्स है, "महत्वपूर्ण प्राधिकरण सेवा एपीआई ऐप सैंडबॉक्स के भीतर समर्थित नहीं है क्योंकि यह विशेषाधिकार वृद्धि को अनुमति देता है।"

यदि इस एपीआई को ऐप को पुनरारंभ करने से पहले प्रमाणीकरण प्रॉम्प्ट प्राप्त करने की आवश्यकता है, तो ऐसा लगता है कि मैं एक्सेसिबिलिटी सुविधा सक्षम किए बिना वैश्विक ईवेंट प्राप्त करने में सक्षम हूं।

सारांश में, मेरी विशिष्ट प्रश्न हैं:

  1. वहाँ कैसे प्रमाणीकरण शीघ्र प्रकट करने के लिए प्राप्त करने के लिए के बारे में मेरे नमूना कोड में कोई त्रुटि है?

  2. प्रमाणीकरण संकेत प्रकट करने के लिए, क्या मुझे प्राधिकरण सेवा API का उपयोग करने के लिए आवश्यक है?

  3. क्या यह संभव है, या संभव नहीं है, एक सैंडबॉक्स वाला ऐप है जिसमें वैश्विक घटनाओं तक पहुंच है?

+0

क्या आप इस के आसपास पाने के लिए प्रबंधन करते थे? मैंने एक ही समस्या पर ठोकर खाई है :( –

+0

सीधे नहीं। वैश्विक हॉटकी के उद्देश्य के लिए, मुझे कोको हॉटकी का उपयोग करने का मार्ग जाना पड़ा। – Geuis

+0

मैं भी उपयोगकर्ता को संकेत देने का एक तरीका ढूंढ रहा हूं। मेरा अनुमान एक इंस्टॉलर है ऐप इंस्टॉल होने पर आवश्यक अनुमतियों के साथ रूट के रूप में चलाया जाएगा और AXMakeProcessTrusted को कॉल करें। यदि इंस्टॉलर मैक ऐप स्टोर है तो इस अनुमति का अनुरोध करने के लिए एक हुक होना चाहिए। – Brennan

उत्तर

0

मुझे गिटहब पर एक संभावित समाधान मिला।

https://github.com/K8TIY/CW-Station

यह एक सहायक आवेदन जो रूट पर चलाया जाएगा मुख्य आवेदन के लिए पहुँच का अनुरोध किया है। यह थोड़ा पुराना है और कुछ कार्यों का उपयोग कर रहा है जिन्हें बहिष्कृत किया गया है, इसलिए मैं इसे आधुनिकीकरण पर काम कर रहा हूं। यह एक अच्छा प्रारंभिक बिंदु की तरह दिखता है।

1

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

4

सबसे पहले, आप ऐप को स्वचालित रूप से एक्सेसिबिलिटी एपीआई का उपयोग करने की अनुमति नहीं दे सकते हैं जो एक सैंडबॉक्स वातावरण में काम करेगा और इस प्रकार ऐप स्टोर में काम करेगा। अनुशंसित तरीका उपयोगकर्ताओं को आसानी से मार्गदर्शन करना है ताकि वे इसे आसानी से सक्षम कर सकें। नई API कॉल AXIsProcessTrustedWithOptions कि वास्तव में है:

 NSDictionary *options = @{(id) kAXTrustedCheckOptionPrompt : @YES}; 
     AXIsProcessTrustedWithOptions((CFDictionaryRef) options); 

अब, अपने पहले और दूसरे सवाल का (सिर्फ पूर्णता के लिए के लिए - फिर से यह खिलौने के डिब्बे में काम नहीं करेगा): AXMakeProcessTrusted के पीछे विचार यह था कि आप वास्तव में एक नया auxiliary application बनाते हैं जिसे आप मुख्य एप्लिकेशन से रूट के रूप में चलाते हैं। इस उपयोगिता के बाद मुख्य आवेदन के निष्पादन योग्य में AXMakeProcessTrusted कॉल किया जाता है। अंत में आपको मुख्य ऐप को पुनरारंभ करना होगा। ओएसएक्स 10.9 में एपीआई कॉल को बहिष्कृत कर दिया गया है।

रूट के रूप में एक नई प्रक्रिया को बढ़ाने के लिए आपको का उपयोग SMJobSubmit का उपयोग करना होगा। यह एक उपयोगकर्ता को एक प्रमाणीकरण संकेत के साथ संकेत देगा कि एक एप्लिकेशन एक सहायक उपकरण स्थापित करने की कोशिश कर रहा है और क्या इसकी अनुमति दी जानी चाहिए। वस्तुतः:

+ (BOOL)makeTrustedWithError:(NSError **)error { 
     NSString *label = FMTStr(@"%@.%@", kShiftItAppBundleId, @"mktrusted"); 
     NSString *command = [[NSBundle mainBundle] pathForAuxiliaryExecutable:@"mktrusted"]; 
     AuthorizationItem authItem = {kSMRightModifySystemDaemons, 0, NULL, 0}; 
     AuthorizationRights authRights = {1, &authItem}; 
     AuthorizationFlags flags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; 
     AuthorizationRef auth; 

     if (AuthorizationCreate(&authRights, kAuthorizationEmptyEnvironment, flags, &auth) == errAuthorizationSuccess) { 
      // this is actually important - if from any reason the job was not removed, it won't relaunch 
      // to check for the running jobs use: sudo launchctl list 
      // the sudo is important since this job runs under root 
      SMJobRemove(kSMDomainSystemLaunchd, (CFStringRef) label, auth, false, NULL); 
      // this is actually the launchd plist for a new process 
      // https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.html#//apple_ref/doc/man/5/launchd.plist 
      NSDictionary *plist = @{ 
        @"Label" : label, 
        @"RunAtLoad" : @YES, 
        @"ProgramArguments" : @[command], 
        @"Debug" : @YES 
      }; 
      BOOL ret; 
      if (SMJobSubmit(kSMDomainSystemLaunchd, (CFDictionaryRef) plist, auth, (CFErrorRef *) error)) { 
       FMTLogDebug(@"Executed %@", command); 
       ret = YES; 
      } else { 
       FMTLogError(@"Failed to execute %@ as priviledged process: %@", command, *error); 
       ret = NO; 
      } 
      // From whatever reason this did not work very well 
      // seems like it removed the job before it was executed 
      // SMJobRemove(kSMDomainSystemLaunchd, (CFStringRef) label, auth, false, NULL); 
      AuthorizationFree(auth, 0); 
      return ret; 
     } else { 
      FMTLogError(@"Unable to create authorization object"); 
      return NO; 
     } 
    } 

पुनरारंभ का सवाल है, यह आम तौर पर भी एक बाहरी सुविधा का उपयोग किया जाता है जो एक मुख्य आवेदन को समाप्त करने के लिए इंतजार कर रहा है और इसे फिर से शुरू होता है (पीआईडी ​​का उपयोग करके) के लिए। आप का उपयोग करते हैं तो आप मौजूदा एक का पुन: उपयोग कर सकते हैं:

NSString *sqlite = @"/usr/bin/sqlite3"; 
    NSString *sql = FMTStr(@"INSERT or REPLACE INTO access values ('kTCCServiceAccessibility', '%@', 1, 1, 1, NULL);", MY_BUNDLE_ID); 
    NSArray *args = @[@"/Library/Application Support/com.apple.TCC/TCC.db", sql]; 
    NSTask *task = [NSTask launchedTaskWithLaunchPath:sqlite arguments:args]; 
    [task waitUntilExit]; 

हालांकि यह से एप्लिकेशन को अयोग्य हो जाएंगे:

 + (void) relaunch { 
     NSString *relaunch = [[NSBundle bundleForClass:[SUUpdater class]] pathForResource:@"relaunch" ofType:@""]; 
     NSString *path = [[NSBundle mainBundle] bundlePath]; 
     NSString *pid = FMTStr(@"%d", [[NSProcessInfo processInfo] processIdentifier]); 
     [NSTask launchedTaskWithLaunchPath:relaunch arguments:@[path, pid]]; 
     [NSApp terminate:self]; 
    } 

एक अन्य विकल्प /Library/Application Support/com.apple.TCC/TCC.db SQLite डेटाबेस मैन्युअल रूप से एक सहायक सहायक का उपयोग कर अनुमतियां जोड़ने हैक करने के लिए है ऐप स्टोर होने के नाते। इसके अलावा वास्तव में सिर्फ एक हैक है और डीबी/स्कीमा किसी भी समय बदल सकता है। कुछ एप्लिकेशन (उदा। Divvy.app ऐसा करने के लिए प्रयुक्त होता है) इस इंस्टॉलर को एप्लिकेशन इंस्टॉलर पोस्ट इंस्टॉल स्क्रिप्ट के भीतर उपयोग किया जाता है। इस तरह संवाद से यह कहता है कि एक ऐप एक सहायक उपकरण स्थापित करने का अनुरोध कर रहा है।

+0

विकल्प संख्या 2 (सीधे उपयोगकर्ता के गोपनीयता ट्रस्ट डेटाबेस को बदलना) होगा लगभग निश्चित रूप से मैक ऐप स्टोर से अपने ऐप को अयोग्य घोषित कर दें क्योंकि यह एक निजी एपीआई का उपयोग करेगा, सिस्टम फाइल को संशोधित करेगा, और एप्लिकेशन सैंडबॉक्स तोड़ देगा। ऐप्पल ने यह भी कहा है कि यदि लोग भरोसेमंद ऐप भेजना शुरू करते हैं तो वे इस विधि की व्यवहार्यता को खत्म कर देंगे इस पर – Draxillion

+0

@Draxillion - धन्यवाद! मैंने इसे स्पष्ट किया। – fikovnik

+0

@Draxillion - क्या आप एक दिमाग देना चाहते हैं ऐप्पल स्टेटमेंट से लिंक? – fikovnik