سؤال

في OS X ، كيف يمكنني إعادة تشغيل تطبيقي تلقائيًا بعد سحب إصدار محدث؟

لقد نظرت حولي بعضًا ويبدو أن LaunchD هي الطريقة المحتملة للقيام بذلك ، لكن لا يبدو لي أن أحصل على رأسي حوله. لا يمكنني العثور على أي موارد جيدة تتحدث عن هذا على وجه التحديد.

يمكنني أيضًا إنشاء برنامج نصي أو عملية منفصلة للقيام بذلك ، لكن هذا يبدو متضايقًا في أحسن الأحوال ، أتوقع أن يكون هناك حل أفضل هناك.

هل كانت مفيدة؟

المحلول

عملية منفصلة هي حل جيد ، انظر إلى Farkle Framework (معظم التطبيقات تستخدمها في AutoPdating) ، كما أنها تستخدم هذا التطبيق المستقل - https://github.com/andymatuschak/sparkle/blob/master/relaunch.m

نصائح أخرى

مجرد التوسع في إجابة جوليا ، حيث اضطررت إلى إعادة تشغيل تطبيقي لسبب آخر من التحديث ، نظرت إلى كيف يفعل Sparkle -

أحدث إصدار (اعتبارًا من 11/2011) من Sparkle لديه هدف للمشروع يسمى Finish_installation.App مدرج في الموارد في إطار التألق. Sparkle ، الذي يعمل كجزء من التطبيق المضيف ، نسخ Finish_application إلى دليل Application_Support ويستخدم تشغيله لتشغيله القابل للتنفيذ الثنائي مثل هذا ، ويمرر في معرف عملية المضيف ومسار إعادة التشغيل:

NSString *relaunchToolPath = [NSString stringWithFormat:@"%@/finish_installation.app/Contents/MacOS/finish_installation", tempDir];
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, relaunch ? @"1" : @"0", nil]];
[NSApp terminate:self];

يبدو أنه مع هذه الوظيفة ، عندما يتم إيقاف العملية الوالدية (؟) ، يتم إطلاق الوالد لـ Finish_application.

Finish_installation ينتظر اختفاء معرف العملية الذي تم تمريره ، كما أن لديه فحصًا أوليًا لمعرفة ما إذا كان يتم إطلاق الوالد (PID = 1)

if(getppid() == 1)...
if (GetProcessForPID(parentprocessid, &psn) == procNotFound)...

ثم يطلق التطبيق مع:

[[NSWorkspace sharedWorkspace] openFile: appPath];

آخر المثير للاهتمام: إذا استغرق التثبيت وقتًا طويلاً ، فإن Finish_installation يغير نفسه إلى عملية مقدمة حتى يتمكن المستخدم من رؤية أن بعض التطبيقات يعمل:

ProcessSerialNumber     psn = { 0, kCurrentProcess };
TransformProcessType( &psn, kProcessTransformToForegroundApplication );

مدونة المصدر

- (void) restartOurselves
    {
       //$N = argv[N]
       NSString *killArg1AndOpenArg2Script = @"kill -9 $1 \n open \"$2\"";

       //NSTask needs its arguments to be strings
       NSString *ourPID = [NSString stringWithFormat:@"%d",
                      [[NSProcessInfo processInfo] processIdentifier]];

       //this will be the path to the .app bundle,
       //not the executable inside it; exactly what `open` wants
       NSString * pathToUs = [[NSBundle mainBundle] bundlePath];

       NSArray *shArgs = [NSArray arrayWithObjects:@"-c", // -c tells sh to execute the next argument, passing it the remaining arguments.
                    killArg1AndOpenArg2Script,
                    @"", //$0 path to script (ignored)
                    ourPID, //$1 in restartScript
                    pathToUs, //$2 in the restartScript
                    nil];
       NSTask *restartTask = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:shArgs];
       [restartTask waitUntilExit]; //wait for killArg1AndOpenArg2Script to finish
       NSLog(@"*** ERROR: %@ should have been terminated, but we are still running", pathToUs);
       assert(!"We should not be running!");
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top