HTML

Hackstock

Hack the planet! Hackers unite!

Címkék

Címkefelhő

UIKeyboard avagy szaporítsuk a szót

2007.12.19. 17:41 :: theshadow

Azon gondolkoztam, hogy ha már szöveget tudunk megjeleníteni, akkor foglalkoznunk kellene a bevitellel is. Ennek az eszköze a billentyűzet, amely szintén View-ként működik a telefonon.
Szerintem ezzel nagyon sokat elárultam róla, hogy hogyan kell használni, elhelyezni. Fontos megjegyezni, hogy mielőtt allokálnánk és inicializálnánk egy példányt, szükség van egy statikus inicializálásra is. Egyes írások szerint az initWithFrame hívása előtt kell ezt elvégezni. Ez sem bonyolult.
[UIKeyboard initImplementationNow];
Az inicializáláshoz szükségünk van az objektum méreteire is.
CGSize kbSize = [UIKeyboard defaultSize]; Ezen túl van egy másik függvény is, ami az adott pozícióba elforgatott kijelzőnem megfelelően forgatott billentyűzet méreteit adja meg. Ez a függvény a defaultSizeForOrientation és paraméterként az accelerometernél látott diszkrét forgatási paramétereknek megfelelő értéket várja.
Tegyünk ki egy View-t és egy billentyűzetet! Én ezt így oldottam meg.
    UITextView *tvMessage;
    UIKeyboard *kbKeyboard;

    UIView *vMain = [[UIView alloc]  initWithFrame: rect];

    [...]

    tvMessage = [[UITextView alloc] initWithFrame: CGRectMake(0.0f,0.0f,rect.size.width,rect.size.height - kbSize.height)];
   
    kbKeyboard = [[UIKeyboard alloc] initWithFrame: CGRectMake(0.0f,rect.size.height - kbSize.height,rect.size.width,rect.size.height)];

    [...]

    [vMain addSubview: tvMessage];
    [vMain addSubview: kbKeyboard];
   
    [window setContentView: vMain];
Mondhatni, hogy ezzel készen is vagyunk. Őszintén szólva, amikor nekiálltam az eszköz használatának tanulmányozásához azt vártam, hogy nekem kell elkapkodni a billentyűleütéseket egy callback függvénnyel. De nem! Ennél sokkal egyszerűbben működik. Ahol áll a kurzor, ott szerkeszi a mezőt - abban az esetben, ha az szerkeszthető - csak bele kell bökni, hogy megjelenjen a kurzor és már lehet is pötyögni.
   
Ezen túl még szabályozhatjuk, hogy a "return" gomb milyen felirattal illetve formában jelenjen meg. A setDefaultReturnKeyType metódusnak adott értékkel állíthatjuk be, amire a következő enumerációs típust vezettem be.
typedef enum
{
  UIKeyboardReturnKeyReturn = 0,    // Return (gray background)
  UIKeyboardReturnKeyGo = 1,            // Go (blue background)
  UIKeyboardReturnKeyGoogle = 2,    // Google (blue background)
  UIKeyboardReturnKeyJoin = 3,        // Join (blue background)
  UIKeyboardReturnKeyNext = 4,        // Next (gray background)
  UIKeyboardReturnKeyRoute = 5,        // Route (blue background)
  UIKeyboardReturnKeySearch = 6,    // Search (blue background)
  UIKeyboardReturnKeySend = 7,        // Send (blue background)
  UIKeyboardReturnKeyYahoo = 8        // Yahoo! (blue background)
} UIKeyboardReturnKeyType;
Van még egy setPreferredKeyboardType metódus, amivel elméletileg a billentyűzet típusát lehet beállítani. Azért írtam, hogy elméletileg, mert nekem nem sikerült viszont találtam róla leírást. Meg kell jegyezni, hogy a beállítás megtétele után a showPreferredLayout eljárást is meg kell hívni, hogy érvényesüljön.
    [kbKeyboard setPreferredKeyboardType:UIKeyboardBlackDefault];
    [kbKeyboard showPreferredLayout];
Ezekre az értékekre is elkészítettem az enumerációs típust.
typedef enum
{
  UIKeyboardDefault = 0,                // default QWERTY layout
  UIKeyboardNumeric = 1,                // numeric/punctuation layout
  UIKeyboardPhone = 2,                    // phone keypad
  UIKeyboardURL = 3,                        // URL layout
  UIKeyboardSMS = 4,                        // SMS (?) layout, shift disabled, num key goes to phone keypad
  UIKeyboardBlackDefault = 5,        // black version of default layout
  UIKeyboardSpartan = 6,                // spartan phone keypad
  UIKeyboardBlackSpartan = 7,        // black spartan (clean!)
  UIKeyboardEmailWithSpace = 8,    // email keypad w/ space key
  UIKeyboardEmailWithAt = 9            // email keypad w/ @ instead of space
} UIKeyboardType;
Ha valaki ez utóbbiba életet tud lehelni, nyugodtan jelezzen. ...és egyébként is hozzá lehet szólni, kérdezni vagy jelezni, hogy mit látna a nagyérdemű szívesen.

Szólj hozzá!

Címkék: iphone appdev

Lokalizált erőforrások iTunes-ban

2007.12.09. 20:36 :: theshadow

Ezúttal evezzünk más vizekre.
Egyszer iTunes-t debug-oltam és a felugró ablak helyét akartam elkapni a programkódban, de nem találtam rá, mert nem MessageBox metódust használt, hanem egy teljesen egyedi megoldást.
Mielőtt munkához látnánk hatástalanítsuk a debugger detektálást a programban, mert jelen állapotában az OllyDbg-t valamint társait észreveszi és nem hajlandó elindulni megfigyelt környezetben. Szerencsére előttünk már megtalálták a megfelelő helyet, ahol valamit kell tennünk. Leírások szerint a 84 C0 74 08 6A 00 byte sorozatot kell megkeresnünk az iTunes.exe-ben, amit a 7.5.0.20-as verzió .004F4B1C offszetén találtam meg. Itt egy függvényhívás található.

.text:004F4B17                 call    debuggerCheck
.text:004F4B1C                 test    al, al
.text:004F4B1E                 jz      short loc_4F4B28
.text:004F4B20                 push    0               ; uExitCode
.text:004F4B22                 call    ds:ExitProcess

Láthatjuk, hogy ha a visszatérési érték nem nulla értékű, akkor a futás befejeződik. Ennek megfelelően módosítottam a rutint, hogy minden esetben nulla értéket adjon vissza.

.text:00418D30 ; int __cdecl debuggerCheck()
.text:00418D30 debuggerCheck   proc near               ; CODE XREF: sub_4F4B00+17p
.text:00418D30                 call    sub_418B00
.text:00418D35                 test    al, al
.text:00418D37                 jz      short loc_418D3C
.text:00418D39
.text:00418D39 loc_418D39:                             ; CODE XREF: debuggerCheck+13j
.text:00418D39                 jmp     short loc_418D4B
.text:00418D39 ; ---------------------------------------------------------------------------
.text:00418D3B                 db 0C3h ; +
.text:00418D3C ; ---------------------------------------------------------------------------
.text:00418D3C
.text:00418D3C loc_418D3C:                             ; CODE XREF: debuggerCheck+7j
.text:00418D3C                 call    sub_418B80
.text:00418D41                 test    al, al
.text:00418D43                 jnz     short loc_418D39
.text:00418D45                 call    ds:IsDebuggerPresent
.text:00418D4B
.text:00418D4B loc_418D4B:                      ; CODE XREF: debuggerCheck:loc_418D39j
.text:00418D4B                 xor     eax, eax
.text:00418D4D                 nop
.text:00418D4E                 nop
.text:00418D4F                 nop
.text:00418D50                 retn
.text:00418D50 debuggerCheck   endp

Keresgélés és file-ok nézegetése után megtaláltam, hogy a regionalizált üzenetek egy sajátos erőforrásfile-ban találhatók a iTunes\iTunes.Resources\en.lproj\Localizable.strings file-ban. A könyvtárban még található egy iTunesLocalized.dll is, ami az előbb említett file-t tölti be. Tehát azt a pontot kell megtalálnunk, hogy mely ponton töltődik be a DLL.
A nyomkövetés kalandjait nem említem meg, hanem csak az eredményeket mutatom meg. Az "iTunesLocalized" szöveget unicode formátumban a .00FBE7F0 offszeten találtam meg, amire .01099AB0 címet találhatunk hivatkozást. Ezt a mutatót a .004F87A6 címen levő kód olvassa be.

.text:004F87A0                 mov     edx, module4    ; iTunesRegistry
.text:004F87A6                 mov     eax, module3    ; iTunesLocalized
.text:004F87AB                 mov     ecx, module2    ; iTunes
.text:004F87B1                 push    edx             ; module4
.text:004F87B2                 mov     edx, iTunesModuleName ; iTunes
.text:004F87B8                 push    eax             ; module3
.text:004F87B9                 push    ecx             ; module2
.text:004F87BA                 push    edx             ; module1
.text:004F87BB                 call    initResourceModules

Némi alakítgatás ereményeként látható, hogy egy erőforrás inicializáló eljárás kapja meg néhány másik modul neve társaságában (iTunesRegistry, iTunesLocalized, iTunes).

.text:0047BAB8                 call    getResourceDLLName ; EDI: DLL name
.text:0047BABD                 mov     ebp, ds:LoadLibraryW
.text:0047BAC3                 mov     eax, esi
.text:0047BAC5                 push    eax             ; lpLibFileName
.text:0047BAC6                 call    ebp ; LoadLibraryW
.text:0047BAC8                 test    eax, eax
.text:0047BACA                 mov     addrITunesRegistry, eax
.text:0047BACF                 jz      short failedInitialization

Az iTunesRegistry.dll-t az iTunes.Resources könyvtárban keresi és próbálja betölteni.

.text:0047BAD1                 movzx   ecx, defaultLocalization
.text:0047BAD8                 mov     edi, [esp+224h+var_210]
.text:0047BADC                 push    ecx
.text:0047BADD                 xor     ecx, ecx        ; int
.text:0047BADF                 mov     eax, ebx
.text:0047BAE1                 call    getLocalizedDLLName
.text:0047BAE6                 add     esp, 4
.text:0047BAE9                 mov     edx, esi
.text:0047BAEB                 push    edx             ; lpLibFileName
.text:0047BAEC                 call    ebp ; LoadLibraryW
.text:0047BAEE                 test    eax, eax
.text:0047BAF0                 mov     addrITunesLocalized, eax
.text:0047BAF5                 jz      short failedInitialization

Lokalizált erőforrás-könyvtárból próbálja meg betölteni az iTunesLocalized.dll-t (iTunes.Resources\en.lproj).

.text:0047BAFD                 call    getResourceDLLName ; EDI: DLL name
.text:0047BB02                 mov     eax, esi
.text:0047BB04                 push    eax             ; lpLibFileName
.text:0047BB05                 call    ebp ; LoadLibraryW
.text:0047BB07                 test    eax, eax
.text:0047BB09                 mov     addrITunesDLL, eax
.text:0047BB0E                 jnz     short loc_47BB2E

Szintén az iTunes.Resources könyvtárból próbálja meg betölteni az iTunes.dll file-t. Emlékezzünk vissza, hogy a betöltött modulok címét hova töltöttük be.

.data:013B2720 addrITunesLocalized dd ?  ; DATA XREF: getResourceModulAddress+14
.data:013B2720                                         ; sub_47B370+9r ...
.data:013B2724 addrITunesDLL   dd ?       ; DATA XREF: initResourceModules+C9
.data:013B2728 addrITunesEXE   dd ?       ; DATA XREF: initResourceModules+F6
.data:013B272C dword_13B272C   dd ?     ; DATA XREF: initResourceModules+FB

Az első elem keresztreferenciái között egy kis függvény érdekes a számunka.

.text:0047B370 ; int __cdecl getITunesLocalizedModuleBase()
.text:0047B370 getITunesLocalizedModuleBase proc near  ; CODE XREF: sub_41E930+CCp
.text:0047B370                                         ; sub_41EAD0+14p ...
.text:0047B370 mov     al, byte_13B271D
.text:0047B375 neg     al
.text:0047B377 sbb     eax, eax
.text:0047B379 and     eax, addrITunesLocalized
.text:0047B37F retn
.text:0047B37F getITunesLocalizedModuleBase endp

Az eljárás jól láthatóan az iTunesLocalized.dll báziscímét adja vissza abban az esetben, ha megtörtént már az inicializáció ezelőtt. Ezt az eljárást több másik is hívjak, amelyek lokalizált erőforrásokat akarnak elérni. A báziscímet handlerként használják fel olyan rendszerhívásokhoz, amelyek dialógusokat vagy bármi mást próbálnak betölteni.
Ez a rutin mellett egy másikra is érdemes odafigyelni, amit ugyancsak az addrITunesLocalized referenciái között találhatunk meg.

.text:0047B350 ; int __cdecl getResourceModulAddress(byte counter)
.text:0047B350 getResourceModulAddress proc near       ; CODE XREF: LoadStringWLocalized+4Fp
.text:0047B350                                         ; LoadStringALocalized+3Cp ...
.text:0047B350
.text:0047B350 counter= byte ptr  4
.text:0047B350
.text:0047B350 cmp     byte_13B271D, 0
.text:0047B357 jz      short loc_47B36C
.text:0047B359 mov     al, [esp+counter]
.text:0047B35D cmp     al, 4
.text:0047B35F jnb     short loc_47B36C
.text:0047B361 movzx   eax, al
.text:0047B364 mov     eax, addrITunesLocalized[eax*4]
.text:0047B36B retn
.text:0047B36C ; ---------------------------------------------------------------------------
.text:0047B36C
.text:0047B36C loc_47B36C:                   ; CODE XREF: getResourceModulAddress+7
.text:0047B36C                                         ; getResourceModulAddress+Fj
.text:0047B36C xor     eax, eax
.text:0047B36E retn
.text:0047B36E getResourceModulAddress endp

Annyival tud többet, hogy a tábla paraméter által meghatározott elemének báziscímét adja vissza. A kép akkor áll össze, ha tovább lépünk a hivatkozó eljárásokra, ahol azt látjuk, hogy LoadStringA, LoadStringW, LoadMenuA, LoadIconA, LoadCursor, LoadImage és még hasonló eljárások segítségével keres egy erőforrást és amint sikerül betöltetni, megszakítja a keresést.
Megpróbáltatásaink itt koránt sem érnek véget. Vizsgáljuk tovább a getITunesLocalizedModuleBase függvényt hívó eljárásokat. Találni fogunk egy .0041E9FC hivatkozást, ami dialógus ablak megjelenítésének a programja. Mivel ez a függvény generikusnak néz ki (paraméterei: template név, dialógus callback függvény, üzenet), ezért az ő hívói között kell kutatnunk, amig rá nem találunk a .004A1306 címre, ami már sokkal szimpatikusabb, de még mindig nem az igazi. Ugyan látható, hogy paraméterezéshez fix callback függvény címet és sablonnevet ad át (GenericUserMessageDlg), de az üzenet konkretizálása még mindig nincs meg. Hol kapja akkor meg ezt a paramétert, mert a jelent eljárás paraméterei között nem. Figyelmesen vizsgálva ráakadhatunk az EDI regiszterre, amit egy buffer átalakító eljárásnak ad át és előzőleg nem inicializálta sehol sem. Nézzük meg, honnan kerül ide a vezérlés.

.text:004A1370 ; int __cdecl showGenericUserMessageDlg(int message, int)
.text:004A1370 showGenericUserMessageDlg proc near     ; CODE XREF: sub_49EF60+3Dp
.text:004A1370                                         ; sub_4AD0C0+45p ...
.text:004A1370
.text:004A1370 message= dword ptr  4
.text:004A1370 arg_4= dword ptr  8
.text:004A1370
.text:004A1370 push    esi
.text:004A1371 mov     esi, [esp+4+arg_4]
.text:004A1375 push    edi
.text:004A1376 mov     edi, [esp+8+message]
.text:004A137A push    7F04h
.text:004A137F push    0
.text:004A1381 call    innerGenericUserMessageDlg
.text:004A1386 add     esp, 8
.text:004A1389 pop     edi
.text:004A138A pop     esi
.text:004A138B retn
.text:004A138B showGenericUserMessageDlg endp

így már érthetőbb, azonban még ez sem legyen elég. Sok helyről hívják, de minden referencia környezetében egyvalami közös; mindenütt egy függvényhívás szerepel előtte, aminek a címe .00490720 és furcsa módon két konstans értéket ad át.

.text:00490720 ; void __cdecl getLocalizedMessageByResourceID(int returnBuffer, __int16 majorResourceID, int minorResourceID)
.text:00490720 getLocalizedMessageByResourceID proc near ; CODE XREF: sub_4116D0+122p
.text:00490720                                         ; sub_4116D0+143p ...
.text:00490720
.text:00490720 returnBuffer= dword ptr  4
.text:00490720 majorResourceID= word ptr  8
.text:00490720 minorResourceID= dword ptr  0Ch

Ez a függvény felelős az erőforrás azonosítók alapján történő szövegek kifejtéséért.
Most játszunk egy kicsit. Tegyünk le ennek a függvénynek az elejére egy megszakítást és adjuk meg a következő feltételt:
Word(esp+8) == 0xA3 && Word(esp+0xC) == 0x58
Most válasszunk ki a listából egy dalt, jobb katt és "Create ringtone...". A futásnak meg kell állni a .00490720 címen, ha mindent jól csináltunk. A Localizable.string file-ban pedig keressük meg az alábbi sort.

"163.088" = "You can create iPhone ringtones from many songs purchased from the iTunes Store.";

Igen, ez fog megjelenni és ez az eljárás kereste elő (163 = 0xA3, 088 = 0x58).

Hadd jegyezzem még itt meg, hogy nagyon sok függvény és változónév nem adott a visszafejtés során. Nagy segítségemre volt az IDA Pro 5.2 abban, hogy én adjam meg a neveket, illetve a már értelmezett eljárásoknak C szintakszisú szignaturákat definiáljak és ezek szerte a kódban úgy jelenjenek meg.

Szólj hozzá!

Címkék: itunes x86

Accelerometer

2007.12.09. 16:39 :: theshadow

Ezúttal a telefon accelerometerével fogunk játszani egy kicsit. Ez az egység, ami meg tudja határozni a térbeli pozícióját. Nem kell nagy dolgokra gondolni, ez nem GPS vagy valami hasonló; csupán azt tudja, hogy a telefon képernyővel felfelé, lefelé, oldalra döntve vagy éppen fejtetőn áll. Ezen a durva felosztáson túl sokkal finomabb meghatározásra is képes.
Nem nagy mágia ezek meghatározása. A UIApplication objektum két callback függvényét fogjuk használni.
- (void)deviceOrientationChanged:(struct __GSEvent *)event
Minden esetben meghívódik, ha a telefon térbeli elhelyezkedése megváltozik. Ebben az esetben a UIHardware deviceOrientation metódusával kérdezhetjük le, hogy a készülék melyik oldalára fordítva helyezkedik el.
- (void)deviceOrientationChanged:(struct __GSEvent *)event
{
    int orient = [UIHardware deviceOrientation: YES];
    NSString *message;
    switch(orient){
        case 0: message = @"Flat, screen upward";
            break;
        case 1: message = @"Normal position";
            break;
        case 2: message = @"Upside down";
            break;
        case 3: message = @"Rotated left";
            break;
        case 4: message = @"Rotated right";
            break;
        case 5: message = @"Changing orientation (?)";
            break;
        case 6: message = @"Screen downward";
            break;
        default:
            message = @"Unknown";
    }
    [tvMessage setText: message];
}
Nem gyakran ugyan, de előfordul, hogy nem a megfelelő érték villan be rövid időre, de szerintem jól használható azokban az esetekben, ha nincs szükség precízebb felbontásra.
Ellenkező esetben egy másik callback függvényt kell implementálni.
- (void) acceleratedInX: (float)x Y:(float)y Z:(float)z
A kísérletezéshez a következő metódust készítettem el.
- (void) acceleratedInX: (float)x Y:(float)y Z:(float)z
{
    [tvMessage setText: [NSString stringWithFormat:@"Acceleration\nX: %f\nY: %f\nZ: %f", x, y, z]];
}
Azt figyeltem meg, hogy minden iránytényező esetében az értékek -0.45 és +0.45 között ingadoznak. Fórumokban olvastam, hogy -0.5 és +0.5 között vehetnek fel értéket.
   
Nézzük csak, hogyan is működik?
Ha balra döntöm a telefont, akkor X értéke 0-tól a maximum felé tart, míg Y a minimum értéktől 0-hoz. Miután teljesen bal oldalára fordítottam és tovább billentem, hogy fejtetőn álljon, X értéke visszatér 0-hoz, Y pedig a maximumhoz. Tovább fordítva X eléri a minimumot és Y a nullához közelít. Vissza térve az normál állapothoz X ismét a nullához tér vissza és Y is a minimum értékhez.
Most magam felé billentve a készüléket Y a minimum értékből nullához jut el, mire a fejem fölé jut a telefon, Z 0-ból a maximumba. Y a maximumába, Z pedig ismét nullába kerül, mire a telefon megint fejjel lefelé áll. Mire vízszintesbe kerül a telefon Y a nullát fogja elérni, míg Z a minimumát. Ismét visszatérve a normál állapothoz Y értéke minimumon, Z pedig 0-án fog állni.
Az érzékelő gravitációs elvű, tehát nincs értelme függőleges tengely mentén történő elfordulást vizsgálni.
Jó játékot.

Szólj hozzá!

Címkék: iphone appdev

NavigationBar és Transition

2007.12.08. 22:56 :: theshadow

Most két új objektummal fogunk megismerkedni: UITransitionView és UINavigationBar.
A UITransitionView segítségével látványos áttünéseket tudunk megvalósítani két view között. Ilyenek láthatók szerte a telefon programjaiban; ez az, ahol azt látjuk, hogy balra vagy jobbra egymás után csúsznak be a képernyőre az ablakok.
Ahogy a neve is mutatja a UITransitionView a UIView származtatott objektuma, ami a mi szempontunkból azt jelenti, hogy az effektus alkalmazásához ezt a view típust kell elhelyeznünk az adott helyen és ezen belül fogják váltani egymást az el- és előtűnő elemek.
Mielőtt továbblépnénk hadd mutassam meg, hogyan alakítottam át az eredeti header file-t, hogy könnyítésképpen egy enumerációs típust vezessek be, mert ilyen módon számok helyett többet mondó konstansneveket írhatunk (a módosított sorokat más szinekkel jelöltem meg).
UITransitionView.h
#import <UIKit/UIView.h>

typedef enum
{
  UITransitionShiftImmediate = 0,
  UITransitionShiftLeft = 1,
  UITransitionShiftRight = 2,
  UITransitionShiftUp = 3,
  UITransitionFade = 6,
  UITransitionShiftDown = 7
} UITransitionStyle;

@interface UITransitionView : UIView
{
    UIView *_fromView;
    UIView *_toView;
    UIView *_firstResponderToRemember;
    id _delegate;
    struct {
        unsigned int animationInProgress:1;
        unsigned int ignoresInteractionEvents:1;
        unsigned int reserved:30;
    } _transitionViewFlags;
}
+ (double)defaultDurationForTransition:(UITransitionStyle)style;    // IMP=0x323edd94
- (void)_didCompleteTransition:(BOOL)fp8;    // IMP=0x323ede98
- (void)_didStartTransition;    // IMP=0x323ede44
- (void)_markRememberedFirstResponderFromView:(id)fp8;    // IMP=0x323eddf4
- (void)_startTransition:(UITransitionStyle)style withDuration:(float)fp12;    // IMP=0x323ee2f8
- (void)_transitionDidStop:(id)fp8 finished:(id)fp12;    // IMP=0x323ee2b8
- (void)dealloc;    // IMP=0x323edca0
- (id)delegate;    // IMP=0x323ee288
- (double)durationForTransition:(int)fp8;    // IMP=0x323edd08
- (id)fromView;    // IMP=0x323ee264
- (BOOL)ignoresInteractionEvents;    // IMP=0x323ee290
- (id)initWithFrame:(struct CGRect)fp8;    // IMP=0x323edbf4
- (BOOL)isTransitioning;    // IMP=0x323ee274
- (void)notifyDidCompleteTransition:(id)fp8;    // IMP=0x323ee0ec
- (void)setDelegate:(id)fp8;    // IMP=0x323ee280
- (void)setIgnoresInteractionEvents:(BOOL)fp8;    // IMP=0x323ee2a0
- (id)toView;    // IMP=0x323ee26c
- (BOOL)transition:(UITransitionStyle)style fromView:(id)fp12 toView:(id)fp16;    // IMP=0x323ee5fc
- (BOOL)transition:(UITransitionStyle)style toView:(id)fp12;    // IMP=0x323ee058

@end
Használata rendkívül egyszerű. Inicializálni a initWithFrame metódussal tudjuk, mint a UIView-t. Az első megjelenítendő view-t a transition metódus második formájával szoktam megadni.
UITransitionView *trView = [[UITransitionView alloc] initWithFrame: rect];
[trView transition: UITransitionShiftImmediate toView: view1];
Ezt a formát nem csak inicializáláskor használhatjuk, hanem bármikor, amikor view-t akarunk váltani. Az első paraméterben megadott effektussal cserélnek helyet a view-k.
  • UITransitionShiftImmediate: azonnal az új view lesz látható
  • UITransitionShiftLeft: az új view jobbról balra csúszik be
  • UITransitionShiftRight: az új view balról jobbra csúszik be
  • UITransitionShiftUp: lentől felfelé csúszik be az új view
  • UITransitionShiftDown: fentől lefelé csúszik be az új view
  • UITransitionShiftFade: fade-eléssel tűnik elő az új view
[trView transition: UITransitionShiftImmediate fromView: view1 toView: view2];
A transition metódus másik formája a leírások szerint úgy működik, hogy az első view az első paraméterben megadott effektus szerint tűnik el, amíg a második view megjelenik. Az előző transition metódus elméletileg úgy működik, hogy az eredeti view nem mozdul meg, de ezt nem így tapasztaltam. Ha valaki tudná, hogy mi az igazság, világosítson fel.

A UINavigationBar az a panel, amin általában bal és jobb oldalon egy gomb jelenik meg, illetve egy cím látható rajta. Ezek is előfordulnak gyakran az eredeti programokban is és a képernyő felső szélén található.
Az előzőhöz hasonlóan itt is bevezettem egy enumerációs típust.
typedef enum
{
  UINavigationBarNormal = 0,
  UINavigationBarDark = 1,
  UINavigationBarDarkSemitransparent = 2
} UINavigationBarStyle;
Az objektum inicializálása érdemes lekérdezni a navigációs sor alapértelmezett méreteit lekérdezni; defaultSize és defaultSizeWithPrompt.
CGSize nsize = [UINavigationBar defaultSize];
Ebből az értékeket az initWithFrame inicializáló eljárásnak adhatjuk át. A showButtonsWithLeftTitle metódussal adhatjuk meg a bal és jobb oldali gomb feliratát - ahova nil értéket írunk, ott nem fog megjelenni gomb. A navigációs sor stílusa három féle lehet: normál, sötét, sötét félig átlátszó.
   
A sor számára delegált objektumot is adhatunk meg, ami akkor hívódik meg, ha egyik gombot a felhasználó megnyomja. A metódus szignatúrája a következőképpen néz ki.
- (void)navigationBar:(UINavigationBar*)navbar buttonClicked:(int)button

A példaprogramhoz két saját view-t készítettem. Az első egy nagyon egyszerű, amint csak egy navigációs sort helyeztem el.
MainView.h
#import <UIKit/UIView.h>
#import <UIKit/UIView-Hierarchy.h>
#import <UIKit/UINavigationBar.h>

@interface MainView : UIView {
    UINavigationBar *nbMain;
}

- (MainView*)initWithFrame:(CGRect)rect;
- (UINavigationBar*)getNavigationBar;

@end
MainView.m
#import <UIKit/UIHardware.h>
#import <UIKit/UINavigationBar.h>
#import <UIKit/UINavigationItem.h>
#import "MainView.h"

@implementation MainView

- (MainView*)initWithFrame:(CGRect)rect
{
    [super initWithFrame:rect];
   
    CGSize nsize = [UINavigationBar defaultSize];
   
    nbMain = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, 0.0f, rect.size.width, nsize.height)];
    [nbMain pushNavigationItem:[[UINavigationItem alloc] initWithTitle:@"Transition"]];
    [nbMain showButtonsWithLeftTitle:nil rightTitle:@"Log" leftBack:NO];
    [nbMain setBarStyle: UINavigationBarNormal];
   
    [self addSubview: nbMain];
   
    return self;
}

- (UINavigationBar*)getNavigationBar
{
    return nbMain;
}

@end
A másik egy log view lesz, ahova néhány üzenetet fogunk összegyüjteni a program futása során.
LogView.h
#import <UIKit/UIView.h>
#import <UIKit/UIView-Hierarchy.h>
#import <UIKit/UINavigationBar.h>
#import <UIKit/UITextView.h>

@interface LogView : UIView {
    UINavigationBar *nbMain;
    UITextView *tvMessage;
}

- (LogView*)initWithFrame:(CGRect)rect;
- (UINavigationBar*)getNavigationBar;
- (void) appendLogMessage: (NSString *) message;

@end
LogView.m
#import <UIKit/UINavigationBar.h>
#import <UIKit/UINavigationItem.h>
#import "LogView.h"

@implementation LogView

- (LogView*)initWithFrame:(CGRect)rect
{
    [super initWithFrame:rect];
    CGSize nsize = [UINavigationBar defaultSize];
    
    nbMain = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, 0.0f, rect.size.width, nsize.height)];
    [nbMain pushNavigationItem:[[UINavigationItem alloc] initWithTitle:@"Log"]];
    [nbMain showButtonsWithLeftTitle:@"Back" rightTitle:nil leftBack:NO];
    [nbMain setBarStyle: UINavigationBarNormal];
   
    tvMessage = [[UITextView alloc] initWithFrame: CGRectMake(0.0f, nsize.height, rect.size.width, rect.size.height)];
   
    [self addSubview: nbMain];
    [self addSubview: tvMessage];
   
    return self;
}

- (UINavigationBar*)getNavigationBar
{
    return nbMain;
}

- (void) appendLogMessage: (NSString *) message
{
    [tvMessage setText:[[tvMessage text] stringByAppendingString: message]];
}

@end
A főprogram pedig a következőképpen fogja össze a két view-nkat.
TestAppMain.h
#import <UIKit/UIApplication.h>
#import "MainView.h"
#import "LogView.h"

@interface TestAppMain : UIApplication {
    UITransitionView *trView;
    
    MainView *vMain;
    LogView *vLog;
}

@end
TestAppMain.m
#import <UIKit/UIWindow.h>
#import <UIKit/UIHardware.h>
#import <UIKit/UITextView.h>
#import <UIKit/UINavigationBar.h>
#import <UIKit/UITransitionView.h>
#import "TestAppMain.h"

@implementation TestAppMain

- (void) applicationDidFinishLaunching: (id) unused
{
    CGRect rect = [UIHardware fullScreenApplicationContentRect];

    UIWindow *window = [[UIWindow alloc] initWithContentRect: rect];
    
    rect.origin.x = rect.origin.y = 0.0f;
   
    vMain = [[MainView alloc] initWithFrame: rect];
    [[vMain getNavigationBar] setDelegate: self];
    vLog = [[LogView alloc] initWithFrame: rect];
    [[vLog getNavigationBar] setDelegate: self];
   
    trView = [[UITransitionView alloc] initWithFrame: rect];
    [trView transition: UITransitionShiftImmediate toView: vMain];
   
    [window orderFront: self];
    [window makeKey: self];
    [window _setHidden: NO];
   
    [window setContentView: trView];

    [vLog appendLogMessage:@"Application started\n"];
}

- (void)navigationBar:(UINavigationBar*)navbar buttonClicked:(int)button
{
    if ([vMain getNavigationBar] == navbar && button == 0){
        [trView transition: UITransitionShiftLeft toView: vLog];
        [vLog appendLogMessage:@"Transferred to log...\n"];
    }else if ([vLog getNavigationBar] == navbar && button == 1){
        [trView transition: UITransitionShiftRight toView: vMain];
        [vLog appendLogMessage:@"Transferred to main...\n"];
    }
}

@end

Szólj hozzá! · 1 trackback

Címkék: iphone appdev

SQLite3 motor

2007.12.06. 22:52 :: theshadow

Arra gondoltam, hogy az előző programot kicsit tovább fejlesztve bemutathatom, hogyan próbáltam meg elérni a telefon - mondjuk - névjegyzékét.
Az adatbázis a /private/var/root/Library/AddressBook/AddressBook.sqlitedb file-ban található. Zárójelben említem meg, hogy a /private/var/root/Library könyvtárban további adatbázisokat fedezhetünk fel. Talán későbbi post(ok)ban megkísérlem feltárni a szerkezetüket. Egyelőre maradjunk az alapoknál.
A UITextView mintegy log írásra használandó; kiegészítettem az osztályt egy metódussal.
- (void) appendLogMessage: (NSString *) message
{
    [tvMessage setText:[[tvMessage text] stringByAppendingString: message]];
}
Ez csupán a meglevő szöveg végéhez csatolja az új üzenetet (sortörésekre magunknak kell ügyelnünk).
Mielőtt elfelejteném, importok között meg kell említeni az sqlite3 header-jét is.
#import <sqlite3.h>
Ezen túl a make file-ban is meg kell ejteni a szükséges kiegészítést.
LDFLAGS=-lobjc -framework CoreFoundation -framework Foundation -framework UIKit /usr/lib/libsqlite3.0.dylib
A UI inicializálása után bele is vágunk az adatbázis megnyitásába és ha sikerült, lefuttatjuk az első lekérdezést és bezárjuk dolgunk végeztével.
    sqlite3* db;
    char* errmsg;
    int retval = sqlite3_open([@"/private/var/root/Library/AddressBook/AddressBook.sqlitedb" UTF8String], &db);
    if (retval == SQLITE_OK){
        retval = sqlite3_exec(db,[@"select First, Last from ABPerson" UTF8String],&sqlite3_cb,nil,&errmsg);
        sqlite3_close(db);
    }else{
        [self appendLogMessage: [NSString stringWithCString: sqlite3_errmsg(db)]];
    }
Tudom, a hibakezelést lehetne még cizellálni, de példának és bemutatni megteszi. Az sqlite3_open metódus UTF8-as karakterláncot vár és szerencsénkre az NSString osztálynak van konverziós metódusa, ezt használjuk. Ha nem járunk sikerrel, akkor kiírjuk a hibaüzenetet, hátha okosabbak leszünk tőle. Sikeres megnyitás után indítjuk a lekérdezést (minden tételből a kereszt és vezetéknevet olvassuk). Érdekessége az sqlite3_exec függvénynek, hogy második paraméterként egy úgynevezett callback típusú függvény címét kell átadnunk. Ez a függvény nem Object-C stílusú, hanem standard C. Egy ideig gondolkoztam, hogy vajon ezt hogyan kellene megoldani és végül a következő függvényt definiáltam.
int sqlite3_cb(void* usrpar,int count,char** data, char** colnames)
{
    NSString* firstname = data[0] == nil ? @"" : [NSString stringWithUTF8String:data[0]];
    NSString* lastname = data[1] == nil ? @"" : [NSString stringWithUTF8String:data[1]];
    [tvMessage setText:[[tvMessage text] stringByAppendingFormat: @"%@ %@\n",lastname,firstname]];
    return 0;
}
Fontos megjegyezni, hogy a callback függvény az eredményhalmaz minden sorára egyenként hívódik meg. A függvény paraméterként egy saját, bármilyen értéket ad áz első helyen (ez a mi esetünkben nil, ezt adtam meg az sqlite3_exec függvényhívásnál). Második paraméter az eredmény oszlopainak száma.Harmadik paraméter az értékek tömbje és végül az oszlopok nevét is megkapjuk.
Némi varázslat az UTF8-as karaktersor és nil érték körül és formázottan hozzákapcsolom a az eddigi log-hoz. Azt is észrevehetjük, hogy itt nem használtam az appendLogMessage függvényemet. Ennek prózai magyarázata, hogy sem self, sem this referenciával nem tudtam hivatkozni az aktuális példányra.

Szólj hozzá!

Címkék: iphone appdev

HelloWorld alkalmazás

2007.12.02. 11:47 :: theshadow

Az elméletekről térjünk át a gyakorlatra. Minden programnyelven szokás elkészíteni a Hello Világ alkalmazást. Ne legyen ez most sem másként.
Nézzük meg, hogy néz ki a fő függvényt és file-t, ami elindítja az alkalmazásunkat:
HelloWorld.m
#import <UIKit/UIKit.h>
#import "HelloApplication.h"

int main(int argc, char **argv)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    int retval = UIApplicationMain(argc, argv, [HelloApplication class]);
    [pool release];
    return retval;
}
Egyszerűnek tünik. Úgy néz ki a függvény szignatúrája, mint más C alkalmazások esetében; argc a paraméterek száma, argv a paramétereket tartalmazó tömb.
Az NSAutoreleasePool objektum létrehozásával automatikus memóriaszemét-gyüjtés lép életbe, tehát ha egy objektumot a release metódussal fel akarunk számolni csak akkor fog a memóriából törlődni, ha már más referencia nem mutat rá.
A UIApplicationMain fogja elindítani az alkalmazásunkat, amit egy másik forrásfile-ban deklaráltunk.
HelloApplication.h
#import <UIKit/UIApplication.h>

@interface HelloApplication : UIApplication {

}
@end
Az objektum header file-jában nem definiáltunk semmit.
HelloApplication.m
#import <UIKit/UIWindow.h>
#import <UIKit/UIHardware.h>
#import <UIKit/UITextView.h>
#import <UIKit/UIView-Hierarchy.h>
#import "HelloApplication.h"

@implementation HelloApplication

- (void) applicationDidFinishLaunching: (id) unused
{
    CGRect rect = [UIHardware fullScreenApplicationContentRect];

    UIWindow *window = [[UIWindow alloc] initWithContentRect: rect];
   
    rect.origin.x = rect.origin.y = 0.0f;
    UITextView *tvMessage = [[UITextView alloc] initWithFrame: rect];
   
    [tvMessage setText:@"Hello Hackstock!"];
   
    [window orderFront: self];
    [window makeKey: self];
    [window _setHidden: NO];
   
    [window setContentView: tvMessage];

}
Ez itt a lényeg.
A felület felépítését a applicationDidFinishLaunching metódusban kezdjük el, amely akkor hívódik meg, amikor az alkalmazás már betöltődött.
A rect változóba lekérdezzük a teljes képernyőterület méretét, amit egy alkalmazás használghat és már inicializálunk is egy UIWindow-t erre a területre. Ez után egy UITextView-t inicializálunk ugyancsak erre a területre, ami azt jelenti, hogy ő fogja elfoglalni az egész képernyőt. Ráírjuk, hogy "Hello Hackstock!". Az ablak néhány alapbeállítása (előtérbe helyezés és láthatóvá tétel) után a szöveges mezőt is elhelyezzük rajta.
Szinte már kész is van. Már csak le kell fordítani.  Erre a feladatra egy make file-t készjtettem, amit a későbbiekben is felhasználhatunk egy kis átalakjtás után.
make
CC=arm-apple-darwin-gcc
LD=$(CC)
LDFLAGS=-lobjc -framework CoreFoundation -framework Foundation -framework UIKit

all:    Hello

Hello:  build/HelloWorld.o build/HelloApplication.o
    $(LD) $(LDFLAGS) -o prod/HelloWorld $^

build/%.o:    %.m
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

clean:
        rm -f build/*.o prod/HelloWorld
Mielőtt futtatnánk, a forráskódok könyvtárában hozzunk létre egy build és prod könyvtárat. Úgy készítettem el a make file-t, hogy az átmeneti és lefordított alkalmazást már könyvtárakban helyezze el és ne keveredjenek a forrással. Most jutott eszembe, hogy ez még tovább ésszerüsíthető, de ezt legközelebb fogom elkövetni.
Ha hiba nélkül lefutott, akkor a prod könyvtárban elkészül a HelloWorld alkalmazás. Készítsük el mellé a szükséges file-okat, amelyeket már a korábbiakban említettünk (icon.png, Info.plist, PkgInfo).
Utolsó lépésként másoljuk a telefonra az Application könyvtáron belül egy alkönyvtárba (ezt is említettük körábban) és nem feledjük el beálljtani, hogy a programfile-on futtatási jogokkal rendelkezzen legalább a root (a legjobb, ha 755-ös jogot kap). SpringBoard újraindjtását követően látható és elindjtható a remekmű.
   

Szólj hozzá!

Címkék: iphone appdev

Alkalmazásfejlesztés - A kezdet

2007.12.01. 11:46 :: theshadow

Ha elkészítettük a fejlesztő környezetet, akkor ideje lenne belevégni a fejlesztésbe.
A legfontosabb, hogy képbe kerüljünk az Objective-C-vel. C nyelvcsaládba tartozik; ezzel azt hiszem elmagyaráztam a szabályok 90%-át. Az objektumok metódusaira hivatkozás némileg eltér a megszokottól, de nem nehém nehéz megszokni. Az alapséma így néz ki:
[receiver method:argument]
Új objektumpéldány létrehozása is kicsit eltérő. Példányreferencia létrehozása az argumentum nélküli alloc metódussal történik:
[UIWindow alloc]
Ezt követően a konstruktorként funkcionáló metódust kell meghívni, amelyet talán konvencionálisan vagy csupán következetesen init-nek illetve ezt tovább fűzve neveztek el. Maradjunk a UIWindow-nál, aminek két konstruktora van: egy túlterhelt initWithFrame és egy initWithContentRect. Nézzük meg, hogy néz ki egy teljes inicializálás a valóságban:
[[UIWindow alloc] initWithContentRect: [UIHardware fullScreenApplicationContentRect]]
Létrehozunk egy UIWindow példányt, inicializáljuk az initWithContentRect metódussal, amelynek egy CGRect típusú paraméter van szüksége. Ezt a UIHardware statikus fullScreenApplicationContentRect függvényéből nyerjük.
Objektumpéldány referenciáját felszabadítani a release fukcióval lehetséges:
[window release]
A leírások alapján nem egyértelmű, hogyan kell több paramétert kezelni, ezért álljon itt egy példa erre is. Egy UINavigationBar példány metódushjvását látjuk:
[nav showButtonsWithLeftTitle: @"Foo" rightTitle: @"Bar" leftBack: YES];
Az első paraméter kivételével mindegyik értéke név szerint adódik át. Első paraméter: @"Foo", második paraméter rightTitle: @"Bar", és a harmadik leftBack: YES.
Ezen a ponton érdemes beszélni a karakterláncok kezeléséről. Természetesen léteznek karaktertömbök és használhatóak a C nyelv beépített funkciói a kezelésükre. Azonban a framework tartalmaz egy saját objektumot erre: NSString. Az egyszerüség miatt új NSString példány létrehozása az 'at' operátorral is lehetséges: @"Foo" és a későbbiekben NSString objektumként kezelhető.
Ezen a ponton pedig térjünk rá egy kényes kérdésre. Hol van mindez dokumentálva, hogy a földi halandó, egyszerű kezdő elindulhasson? Mivel nem hivatalos fejlesztőeszközről beszélünk, ezért meglehetősen sok helyről kell összegyüjtenünk az információkat.
Az Objective-C-t érintő kérdésekben a Apple Develper Connection-t szoktam használni.
A telefon specifikus osztályainak szignatúráját Erica Sadum közzétette a honlapján úgy, ahogy a classdump nevű eszköz visszafejtette. Több mint a semmi. Minden elérhető header file a Cygwin usr/local/arm-apple-darwin/include könyvtárában van; itt is érdemes mazsolázni és akár kibővjteni saját jegyzeteinkkel.
Aki komolyan töri a fejét a fejlesztésen, e header file-ok tanulmányozása erősen ajánlott.

Szólj hozzá!

Címkék: iphone appdev

Saját csengőhangok

2007.11.27. 22:55 :: theshadow

Ugye, hogy felmerült már, hogy egyedi csengőhang kellene, de nem szeretnénk (vagy éppen nem is lehet) iTunes-on $2-t kicsengetni érte? Rablás. Gyártsunk helyette magunknak!
Egy tetszőleges zeneszerkesztővel komponáljuk meg, vágjuk ki, effekteljük, tegyünk vele, amit akarok, de lehetőleg legyen rövidebb 30 másodpercnél. Ha kész a mű mentsük el MP3 vagy éppen WAV formátumba. A lényeg, hogy az iTunes kezelni tudja.
Dobjuk is rögtön a művet az iTunes-ba és konvertáljuk AAC formátumba és keressük meg, hova jött létre az eredmény. Egy M4A file-t kell keresni (Get info és alul látszik az elérési útvonal). Készítsünk róla egy másolatot M4R kiterjesztéssel is. Mindkét állományt másoljuk a telefon /private/var/root/Media/iTunes_Control/Ringtones könyvtárába.
Most menjünk a /private/var/root/Media/iTunes_Control/iTunes könyvtárba és ott nyissuk meg a Ringtones.plist filet, ami így néz ki, amikor nincsenek csengőhangok még regisztrálva benne.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Ringtones</key>
    <dict>

    </dict>
</dict>
</plist>
A legbelső dict tag-ek között kell létrehozni egymás után, csengőhangokként a következő XML darabot:
        <key>[filenév].m4r</key>
        <dict>
            <key>GUID</key><string>[egyedi azonosítószám]</string>
            <key>Name</key><string>[név a listában]</string>
        </dict>
        <key>[filenév].m4a</key>
        <dict>
            <key>GUID</key><string>[egyedi azonosítószám]</string>
            <key>Name</key><string>[név a listában]</string>
        </dict>
A filenév mindkét esetben legyen azonos, úgy, mint az egyedi azonosító és a listában megjelenítendő név is. Még nem tudom mi a két bejegyzés megtételének oka, de fogadjuk el, hogy így működik.
Ez még csak a megoldás egyik fele. Ha most megpróbáljuk a szinkronizálást az iTunes-szal, akkor felülírja a plist file-r és nem jelenik meg a választható hangok között a mienk. Ennek megakadályozására a következő trükköt találtam.
Ha a telefon gyökérkönyvtárában nem szerepelne a iTunes_Control symlink, akkor hozzuk létre:
ln -s /private/var/root/Media/iTunes_Control /iTunes_Control
Most átnevezzük az eredeti Ringtones.plist file-t és egy symlinket készítünk az eredeti nevével:
mv /iTunes_Control/iTunes/Ringtones.plist /iTunes_Control/iTunes/Invincible.plist
ln -s /iTunes_Control/iTunes/Invincible.plist /iTunes_Control/iTunes/Ringtones.plist
Elméletileg kész van, de egyes esetekben nem működik. Próbáljuk ki! Ha a szinkronizálás után a file tartalma újraíródna, akkor tegyük a következőket:
mv /private/var/root/Media/iTunes_Control/iTunes/Ringtones.plist /private/var/root/Media/iTunes_Control/iTunes/Invincible.plist
ln -s /private/var/root/Media/iTunes_Control/iTunes/Invincible.plist /private/var/root/Media/iTunes_Control/iTunes/Ringtones.plist
így már nekem is működött. Az iTunes ugyan sopánkodik, hogy egyes file-okat nem tud szinkronizálni, de ez nem érdekes.

Szólj hozzá!

Címkék: iphone csengőhang

Applications

2007.11.26. 23:32 :: theshadow

The applications are located in /Applications directory, in a directory called like [something].app. Let's take a look what files should we place here to make our application work.
 

  • PkgInfo file, which contains "APPL????"
  • Default.png, the content of this file will remain while the application is loading and starting. We can take it as a splash screen. If this file is not presented then a default one will be displayed. Its size should be 320x460 pixels.
     
  • icon.png, this icon will be placed on , its size should be 59x60
  • Info.plist, the file contains informations about the applications. I found the following template XCode template file, we just need to replace the ${EXECUTABLE_NAME} and com.yourcompany.«PROJECTNAMEASXML» placeholders to our own ones.
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <key>CFBundleExecutable</key>
        <string>${EXECUTABLE_NAME}</string>
        <key>CFBundleIdentifier</key>
        <string>com.yourcompany.«PROJECTNAMEASXML»</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
        <string>1.0</string>
    </dict>
    </plist>
  • the program binary, it is very important to setup the correct access rights after copying it on the phone and grant execute right.

After we places every file to the right location we just need to restart the SpringBoard to see the icon of the new application appearing. In an SSH terminal fire the following command.
 

launchctl stop com.apple.SpringBoard

Szólj hozzá!

Címkék: iphone appdev

iPhone - the beginning

2007.11.26. 23:00 :: theshadow

Like you know every beginning is hard... so I'm not wasting the words; let's create the iPhone developer toolchain. If you seen an error by any of the following steps just try to execute the make clean command and try again. Of course before trying it is worsty to find and fix the problem. I not succeeded for the firswt time..
  1. Cygwin install
  2. Download XCode 2.5 Developer Tools from Apple Developer Center
  3. In Cygwin
    cd /home
    svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm-svn -r 42498
    In an other consolte
    cd /home
    svn checkout http://iphone-dev.googlecode.com/svn/trunk/ iphone-dev
  4. Let's create a copy of the phone file system in usr/local/share/iphone-filesystem directory
  5. Creating LLVM
    cd /home/llvm-svn
    ./configure --enable-optimized
    make ENABLE_OPTIMIZED=1
    make install
    LLVMOBJDIR=`pwd`
  6. Creating ODCCTools
    Let's download in /home/iphone-dev/odcctools directory victzh's patch which is required for Cygwin install
    mkdir /usr/local/arm-apple-darwin
    mkdir -p /home/iphone-dev/build/odcctools
    cd /home/iphone-dev/odcctools
    patch -p0 <odcctools_cygwin.patch
    mv include/foreign/machine include/foreign/_machine
    cd ../build/odcctools
    ../../odcctools/configure --target=arm-apple-darwin --disable-ld64
    make
    make install
  7. Extract Packages/Packages/MacOSX10.4.Universal.pkg/Contents/Archive.pax.gz file from XCode 2.5 Developert Tools and unpack it
    gunzip -c Archive.pax.gz | cpio -i
  8. Installing iPhone headers
    HEAVENLY=/usr/local/share/iphone-filesystem
    cd /home/iphone-dev/include
    ./configure --with-macosx-sdk=/SDKs/MacOSX10.4u.sdk
    bash install-headers.sh
  9. Creating CSU
    mkdir -p /home/iphone-dev/build/csu
    cd /home/iphone-dev/build/csu
    ../../csu/configure --host=arm-apple-darwin
    make install
  10. Compiling LLVM-GCC (very important to have the right path in $LLVMOBJDIR and $HEAVENLY
    mkdir -p /home/iphone-dev/build/llvm-gcc-4.0-iphone
    cd /home/iphone-dev/build/llvm-gcc-4.0-iphone
    ../../llvm-gcc-4.0-iphone/configure --enable-llvm=`llvm-config --obj-root` --enable-languages=c,c++,objc,obj-c++ --target=arm-apple-darwin --enable-sjlj-exceptions --with-heavenly=$HEAVENLY --with-as=/usr/local/bin/arm-apple-darwin-as --with-ld=/usr/local/bin/arm-apple-darwin-ld
    make LLVM_VERSION_INFO=2.0-svn-iphone-dev-0.3-svn
    make install
Done, that's all!

Szólj hozzá!

Címkék: iphone toolchain

süti beállítások módosítása