Služby WebKitu - MujMAC.cz - Apple, Mac OS X, Apple iPod

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:

Soutěž

Sponzorem soutěže je:

IDIF

 

Jaký fotograf/ka získal/a cenu za nejpopulárnější příspěvek v Nikon Photo Contest?

V dnešní soutěži hrajeme o:

Seriály

Více seriálů



Software

Služby WebKitu

12. června 2007, 00.00 | V předcházejícím dílu našeho seriálu o programování ve vývojovém prostředí Cocoa jsme se prvně seznámili se třídou WebView, jež je součástí frameworku WebKit. Minule jsme se vlastnímu WebKitu moc nevěnovali: sestavili jsme jednoduchý webový browser s využitím těch nejstandardnějších služeb. Dnes si však o frameworku a jeho možnostech řekneme trochu více.

V předcházejícím dílu našeho seriálu o programování ve vývojovém prostředí Cocoa jsme se prvně seznámili se třídou WebView, jež je součástí frameworku WebKit (nepatří tedy striktně vzato přímo do frameworků Cocoa, jež zahrnují Foundation a AppKit, ale z praktického hlediska je to poměrně jedno a můžeme jistě v rámci popisu prostředí Cocoa zmínit i ostatní objektové knihovny, které Mac OS X standardně nabízí – ostatně kupříkladu knihovnou CoreData jsme se již zabývali). Vzhledem k tomu, že se v současnosti věnujeme tomu, kterak při programování pro Mac OS X řešit problémy se sítí, je rozhodně vhodné několik dílů frameworku WebKit věnovat.

Minule jsme si toho o vlastním WebKitu moc neřekli: sestavili jsme jednoduchý webový browser s využitím těch nejstandardnějších služeb třídy WebView – dokonce ani nebylo zapotřebí napsat jediný řádek zdrojového kódu – a to bylo vše. Dnes si tedy o frameworku a jeho možnostech řekneme trochu více.

Struktura frameworku

Ačkoli WebKit obsahuje řadu tříd a protokolů, jedná se o víceméně jednoúčelovou knihovnu – jejím základem je třída WebView a její služby; ostatní třídy toliko doplňují a rozšiřují základní možnosti třídy WebView.

Jak již víme, instance třídy WebView v zásadě reprezentuje "webovou stránku" (ve skutečnosti nabízí služby poněkud bohatší – nejen že se stará o načítání dat ze serveru, ale dokáže také udržovat přehled o historii a podobně).

Vzhledem k tomu, že webová stránka často bývá složena z řady stránkových rámů (frames), má WebView poměrně složitou vnitřní strukturu, založenou na hierarchické struktuře instancí třídy WebFrame; každá z nich pak obsahuje instanci třídy WebFrameView, jež se stará o zobrazení obsahu patřičného rámce. S touto strukturou málokdy potřebujeme pracovat přímo; výjimkou je nutnost procházení hierarchické struktury rámců, chceme-li využít přímého přístupu k objektům ve stránce (např. pro vyplňování formulářů), leč takovým věcem se budeme věnovat až později. Prozatím tedy zůstaneme jen u přístupu k hlavnímu rámci pomocí standardní zprávy mainFrame pro případ, kdy chceme programově určit požadované URL.

Hned po vlastní struktuře WebView lze za nejdůležitější považovat neformální protokoly delegátů. Těm proto věnujeme samostatné odstavce; zatím si řekneme jen tolik, že třída WebView je uzpůsobena tak, aby mohla spolupracovat s několika řídícími objekty – delegáty –, které přesně určují její chování. Jedná se v zásadě o týž mechanismus, jakým jsou nám dávno známé delegáty tříd typu NSWindow; rozdílem je pouze to, že WebView namísto jediného podporuje delegátů několik (ovšem nic nebrání tomu, aby role všech delegátů zastoupil jeden společný objekt).

Z dalších pomocných tříd může být zajímavý WebScriptObject, který umožňuje velmi pohodlnou a účinnou spolupráci mezi programem v Objective C a JavaScriptovými moduly uloženými přímo v samotné stránce. Méně často přímo využíváme služeb tříd WebDataSource, jež reprezentuje konkrétní data uložená ve stránce a umožňuje i přidávat vlastní formáty – WebView pro tento účel nabízí vlastní systém pluginů pro dynamické zavádění těchto formátů nebo WebDownload, jejímž prostřednictvím můžeme řídit načítání dat z Webu přímo do souborů.

GUI

První a patrně nejčastěji využívaný z delegátů třídy WebView je delegát řídící grafické uživatelské rozhraní. Třída WebView totiž sice prostřednictvím svých podřízených WebFrameView zobrazí kompletní webovou stránku a interpretuje i ty služby grafického uživatelského rozhraní, jež se stránkou přímo souvisejí – klepnutí na odkaz a podobně –, avšak samozřejmě nemůže sama přímo zajistit pomocné služby GUI, jako je zobrazení "alertů", výběr souboru pro "upload" a podobně.

K tomu právě slouží delegát pro GUI – objekt, specifikovaný pomocí standardní služby setUIDelegate:. Objekt může interpretovat dlouhou řadu metod z neformálního protokolu WebUIDelegate, který řídí otevírání nových oken, výše zmíněné alerty apod.

Frame a resource loading

Další dvojici pomocných objektů lze "instalovat" pomocí služeb setFrameLoadDelegate: a setResourceLoadDelegate:; objekty mohou interpretovat metody z neformálních protokolů WebFrameLoadDelegate a WebResourceLoadDelegate.

Prostřednictvím těchto služeb nabízí WebView detailní přehled načítání dat z webu – chceme-li kupříkladu zobrazovat detailní postup načítání stránky, můžeme jich přímo využít (pro rámcový přehled můžeme také využít toho, že samotné WebView rozesílá notifikace, umožňující zobrazit jednoduchý "progress bar" – to si ukážeme hned příště).

Delegáti pro načítání rámců a zdrojů však umožňují mnohem více: WebFrameLoadDelegate kupříkladu automaticky dostává informace o titulku stránky a o její případné ikoně ("favicon"); prostřednictvím WebResourceLoadDelegate pak lze kupříkladu zakázat načítání obrázků (resp. nahradit je "standardním" obrázkem) apod.

Policy delegate

Poslední z delegátů, o nichž se dnes zmíníme, je objekt, odpovídající neformálnímu protokolu WebPolicyDelegate. Jeho prostřednictvím lze řídit, které typy objektů se načtou a které ne.

Specialita nakonec: chyby JavaScriptu

Ačkoli třída WebView nabízí skutečně přebohaté možnosti řízení a úprav prostřednictvím delegátů (a my si samozřejmě mnohé z nich v příštích dílech našeho seriálu ukážeme na praktických příkladech), jednu poměrně důležitou službu jsem hledal marně – hlášení chyb JavaScriptu.

Analýzou Safari (jež chyby JavaScriptu vypisuje do konsole, pokud tuto službu zapneme v jeho nabídce "debug") se ukázalo, že o toto se stará skrytá třída WebBridge. Její služby nejsou součástí veřejného API WebKitu; proto je třeba si dát pozor na to, že případná úprava nemusí být nutně kompatibilní s budoucími verzemi frameworku. V současnosti však funguje dobře následující kód:

// obecná služba umožňující instalovat vlastní
// metody do již existujících tříd
@implementation NSObject (OCSExtensionsCategory)
+(IMP)ocsReplaceSelector:(SEL)oldSel
      ofClass:(Class)oldCl
      by:(SEL)newSel
      ofClass:(Class)newCl {
  void _objc_flush_caches(Class);
  IMP original=[oldCl instanceMethodForSelector:oldSel];
  if (!original) return NULL;
  struct objc_method *method=class_getInstanceMethod(oldCl,oldSel);
  if (!method) return NULL;
  IMP new=[newCl instanceMethodForSelector:newSel];
  if (!new) return NULL;
  method->method_imp=new;
  _objc_flush_caches(newCl);
  return original;
}
+(IMP)ocsReplaceSelector:(SEL)oldSel by:(SEL)newSel {
  return [self ocsReplaceSelector:oldSel ofClass:[self superclass]
               by:newSel ofClass:self];
}
@end

// vlastní úprava třídy WebBridge
@implementation OCSPrivateWebBridgePatchMethods
static void (*originalAddMessage)(id,SEL,id)=NULL;
-(void)__ocs_addMessage:(NSDictionary*)message {
  originalAddMessage(self,_cmd,message);
  NSString *file=[message objectForKey:@"sourceURL"],*urlprefix=@"";
  NSURL *url=[NSURL URLWithString:file];
  if (![url isFileURL])
    urlprefix=[[file componentsSeparatedByString:
      [url path]] objectAtIndex:0];
  file=[url path];
  NSLog(@"JavaScript error: %@ (%@:%@, %@%@)",
    [message objectForKey:@"message"],
    [file lastPathComponent],
    [message objectForKey:@"lineNumber"],
    urlprefix,
    [file stringByDeletingLastPathComponent]);
}
+(void)installWebBridgePatch {
  Class webBridge=NSClassFromString(@"WebBridge");
  if (!webBridge)
    NSLog(@"Cannot patch WebBridge: does not exist!");
  else
    originalAddMessage=(void(*)(id,SEL,id))
      [self ocsReplaceSelector:
        @selector(addMessageToConsole:)
	   ofClass:webBridge
	   by:@selector(__ocs_addMessage:)
	   ofClass:self];
}
@end

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Tipy a Triky  

 » Rubriky  » Začínáme s  

 » Rubriky  » Software  

Poslat článek

Nyní máte možnost poslat odkaz článku svým přátelům:

Váš e-mail:

(Není povinný)

E-mail adresáta:

Odkaz článku:

Vzkaz:

Kontrola:

Do spodního pole opište z obrázku 5 znaků:

Kód pro ověření

 

 

 

 

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: