Я работаю над приложением MacOS и хотел бы узнать, есть ли способ получить из него URL-адрес активного браузера. Приложение сделано в C ++.
Я хотел бы получить его без использования AppleScript.
Это возможно?
Спасибо
Это не простой ответ, но хорошая новость заключается в том, что «да, это возможно сделать без необходимости использования AppleScript», а плохая новость — «вам придется использовать AppleScript для начала».
Позвольте мне остановиться подробнее: в браузерных приложениях обычно есть словарь Applescript (который можно увидеть с помощью приложения «Редактор сценариев», которое находится в вашем /Applications/Utilities
папка. Вот как выглядит словарь для Google Chrome:
Вы увидите, что я нашел класс «tab» и там вы увидите свойство URL.
Итак, что вам нужно сделать, это создать AppleScript первый чтобы получить окна для браузера, на который вы ориентируетесь. Затем, когда это сработает, вам нужно преобразовать AppleScript в базовый, необработанный AppleEvents (для которого компилируются AppleScripts). И AppleScripts, и AppleEvents могут быть выполнены в коде.
Ответ ты действительно ищешь (например, «могу ли я использовать какой-нибудь сверхсекретный API или отправить URL из моего кода в какой-то открытый порт на моей локальной машине для запроса браузера?»), насколько я знаю, не существует. AppleScript и AppleEvents — это давние способы, которые Apple предоставляет для автоматизации большинства приложений, и вам необходимо использовать это.
Если вы решите использовать AppleScript и, возможно, преобразовать их в AppleEvents, вот что я бы сделал.
1) Найти общедоступные AppleScripts, чтобы сделать работу, которую вы хотите.
2) Конвертировать AppleScript в AppleEvents
3) Используйте AppleEvents.
Для 1, вот сценарий, который проходит через все окна в Safari, которые я получил от этот урок:
tell application "Safari"
--Variables
set windowCount to number of windows
set docText to ""
--Repeat for Every Window
repeat with x from 1 to windowCount
set tabCount to number of tabs in window x
--Repeat for Every Tab in Current Window
repeat with y from 1 to tabCount
--Get Tab Name & URL
set tabName to name of tab y of window x
set tabURL to URL of tab y of window x
end repeat
end repeat
end tell
Для шага 2, я думаю, вы можете использовать панель просмотра аксессуаров в редакторе сценариев чтобы увидеть необработанные события и результаты.
На третьем этапе этот древний код, который я написал на C, получит URL-адрес окна браузера с указанным идентификатором окна.
OSStatus CreateTheAppleEventForGetURL( OSType appSignature, long windowid, char **retval)
{
OSErr err = noErr;
AEAddressDesc targetAddress;
AEDescList replyDesc = { typeNull, nil };
AEKeyword keyword;
DescType desiredClass;
AEDesc replySingle, theOptionalAttributeDesc, theSeldDesc,theObjSpec,theThirdObjSpec,theSecondObjSpec,theFormDesc,theNullDesc;
AppleEvent theEvent, reply;
AEIdleUPP theIdleProc;
Boolean gotReply = false;
long errNumber=0;
long buffer;
Size actualSize;
char *result = NULL;
theIdleProc = NewAEIdleUPP((AEIdleProcPtr)&TheIdleFunction );
if( NULL != theIdleProc )
{
err = AECreateDesc( typeApplSignature, &appSignature, sizeof( appSignature ), &targetAddress );
if( noErr == err )
{
err = AECreateAppleEvent( 'core', 'getd', &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent );
buffer = 0x10000;
err = AECreateDesc('magn', &buffer, 4, &theOptionalAttributeDesc);
if( noErr == err )
{
err = AECreateDesc(typeNull, nil, 0, &theNullDesc);
desiredClass = 'cwin';
buffer = 'ID ';
err = AECreateDesc('enum',&buffer,4,&theFormDesc);
buffer = windowid;
err = AECreateDesc(typeLongInteger,&buffer,4,&theSeldDesc);
err = CreateObjSpecifier(desiredClass,&theNullDesc,'ID ',&theSeldDesc,true,&theThirdObjSpec);
buffer = 'docu';
err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
desiredClass = 'prop';
err = CreateObjSpecifier(desiredClass,&theThirdObjSpec,'prop',&theSeldDesc,true,&theSecondObjSpec);
buffer = 'prop';
err = AECreateDesc('enum',&buffer,4,&theFormDesc);
err = AECreateDesc(typeNull, nil, 0, &theObjSpec);
buffer = 'pURL';
err = AECreateDesc(typeType,&buffer,4,&theSeldDesc);
err = CreateObjSpecifier(desiredClass,&theSecondObjSpec,'prop',&theSeldDesc,true,&theObjSpec);
err = AEPutAttributeDesc(&theEvent,'csig',&theOptionalAttributeDesc);
err = AEPutParamDesc(&theEvent,keyDirectObject, &theObjSpec);
}
if( noErr == err )
{
err = AESend( &theEvent, &reply, kAEWaitReply + kAENeverInteract, kAENormalPriority, 120, theIdleProc, NULL );
if( noErr == err )
{
gotReply = true;
}
else
{
gotReply = false;
}
err = AEDisposeDesc(&theObjSpec);
err = AEDisposeDesc(&theOptionalAttributeDesc);
err = AEDisposeDesc(&theSeldDesc);
err = AEDisposeDesc(&theSecondObjSpec);
err = AEDisposeDesc(&theThirdObjSpec);
err = AEDisposeDesc(&theFormDesc);
err = AEDisposeDesc(&theNullDesc);
}
}
err = AEGetParamPtr(&reply, keyErrorNumber, typeLongInteger, NULL, &errNumber, sizeof(errNumber), &actualSize);
if(true == gotReply )
{
err = AEGetParamDesc( &reply, keyDirectObject, typeAEList, &replyDesc );
keyword = typeAEList;
err = AEGetNthDesc( &replyDesc, 1, typeUnicodeText, &keyword, &replySingle);
if( noErr == err)
{
OSStatus status;
Size theSize;
UnicodeMapping iUnicodeMapping;
UnicodeToTextInfo theInfo;
UniChar theName[512];
unsigned char crapola[512]; // a.k.a. a pstring
iUnicodeMapping.unicodeEncoding = kTextEncodingUnicodeDefault;
iUnicodeMapping.otherEncoding = kTextEncodingMacRoman;
iUnicodeMapping.mappingVersion = kUnicodeUseLatestMapping;
status = CreateUnicodeToTextInfo(&iUnicodeMapping,&theInfo);
theSize = AEGetDescDataSize(&replySingle);
err = AEGetDescData(&replySingle,&theName,512);
if( noErr == err)
{
err = ConvertFromUnicodeToPString(theInfo,theSize,theName,crapola);
if( noErr == err )
{
result = malloc( theSize * sizeof( char ));
if( NULL != result )
{
p2cstrcpy(result,crapola);
printf( "URL returned is %s\n", result);
}
}
}
status = DisposeUnicodeToTextInfo(&theInfo);
}
}
err = AEDisposeDesc( &targetAddress );
err = AEDisposeDesc( &replySingle );
DisposeAEIdleUPP( theIdleProc );
}
if( NULL != retval )
*retval = result;
return(err);
}
Я уверен, что это не скомпилируется, так как ряд Carbon API были обновлены и переименованы начиная с macOS 10.8, но вы поняли.
Надеюсь, это длинное эссе поможет вам!
Других решений пока нет …