[討論] toolchain版本的離線地圖 - iPhone4.TW

會員登入



顯示結果從 1 到 4 共計 4 條
  1. #1
    mask 的頭像

    管理團隊

    註冊日期:10-13-2007
    文章:285
    謝謝你: 4
    在 3篇文章中獲得 3個感謝
    這邊要討論的是如何從別人的程式改起 變成自己的東西
    站在巨人的肩膀 總是比自己單搞看的遠
    (其實是我根本沒辦法從頭開始寫一個程式 XD....)
    還有如何用toolchain開發一個程式(當然SDK也很好 但是偏偏我要寫東西的SDK使用協定不讓我寫XD)

    先抱怨一下

    我實在是搞不定SDK with toolchain
    用 Linux編輯的拿到iPhone上頭也不能用 囧mmmmmm
    所以只能回到iPhone上頭用他的toolchain 2.0編輯軟體
    相當麻煩 有沒有哪位大德 可以教教我怎樣在Mac 上面建立 Toolchain的環境阿?

    好先說明你需要的東西
    1.一個jailbreak的iPhone 軔體版本在2.0以上
    2.透過Cydia 安裝openssh toolchain2.0(相當大喔~~)
    3.一個ssh軟體 讓你可以登入iPhone寫程式
    4. HelloWorld source code在 這邊 還有改過的 HelloWorld source code

    首先先把HelloWorld先給解壓縮到iPhone裡面
    假設你是放在 /var/root/底下
    那程式碼就在 /var/root/HelloWorld/Classes/底下

    裡面有三個檔案
    main.m
    HelloWorld.m
    HelloWorld.h

    main.m ->如果你寫的程式相當小 大致上都不需要改他
    HelloWorld.h -> 將要用到的東西都登記起來
    HelloWorld.m -> 真正的程式碼

    讓我們看看其中一個程式碼
    代碼:
    #import <CoreFoundation/CoreFoundation.h>
    #import <Foundation/Foundation.h>
    #import <UIKit/UIWindow.h>
    #import <UIKit/UIKit.h>
    #import <UIKit/UIApplication.h>
    #import <UIKit/UITextView.h>
    #import <UIKit/UINavigationBar.h>
    #import <UIKit/UIView.h>
    #import <UIKit/UIAccelerometer.h>
    
    *interface HelloWorldApp : UIApplication <UIAccelerometerDelegate> {
        UIView            *mainView;
        UITextView        *textView;
    }
    *end
    前面第一段的#import 跟傳統的 #include是差不多的
    後面的*interface HelloWorldApp: UIApplication
    是宣告一個繼承自UIApplication 的Class叫HelloWorldApp
    <UIAccelerometerDelegate> 這段 原諒我笨.... 我不知道他是幹嘛的....
    {}裡面的就是程式在運作中間都會運用到的變數
    *end代表這個宣告結束了
    你可以宣告很多個Class 或者跟我一樣懶懶得用一個Class搞定一切(當然這會造成維護困難 囧mmm)

    至於HelloWorld.m呢 就是說明 我們這個程式實際要做的事情
    代碼:
    #import "HelloWorldApp.h"
    
    *implementation HelloWorldApp
    - (void) applicationDidFinishLaunching: (id) unused
    {
        UIWindow *window;
    
        window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
        /* Create a text view */
        textView = [[UITextView alloc]
            initWithFrame: CGRectMake(0.0f, 48.0f, 320.0f, 100.0f)];
        [textView setText:*"Ciao"];
    
        /* Create a main view, and add our text view as subview */
        mainView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
        [mainView addSubview:textView];
    
        /* Setup window */
        [window makeKeyAndVisible];
        [window addSubview: mainView];
    }
    *end
    很簡短 所以很好解釋
    首先你可以看到第一行 #import "HelloWorld.h" 你要先把你剛剛設訂的東西給包括進來
    代碼:
    *implementation HelloWorldApp
    ...
    *end
    代表Class HelloWorldApp實作的部份
    裡頭有的唯一一個function叫做 - (void) applicationDidFinishLaunching: (id) unused
    這個function會在程式被開啟的時候被呼叫(所以你想像他就是整個程式的啟始點就好了)
    詳細的Objective-C語法說明 請參閱chenhai在OIKOS的精闢講解
    看到這個function的裡面
    代碼:
        UIWindow *window; //每一個程式都需要一個基本視窗 底下是他的標準起始方法
    
        window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
        /* 新增一個 TextView 所有CocoaTouch的視窗Class都會前綴一個UI 來做區別 *\
            而UITextView 你簡單想成一個文字方塊就好了,後面的initWithFrame: 代表
            你需要傳第一個框架給這個TextView 告訴他他自己有多大 這樣iPhone才畫的
            出來。
            CGRectMake就是幫助你畫出這個框架的工具 第一個0.0f代表從畫面左上角原
            點算起X軸的位置 第二個48.0f代表Y軸位置 第三個320.0f代表框架長度 100.
            0f代表寬度 所以這就是一個 從畫面左上角原點算起 向下48.0f距離 大小320X
        \* 100 的方塊 而他的文字內容是[at]"Ciao" Objective-C的字串 前面要加上[at]*/
    
        textView = [[UITextView alloc]
            initWithFrame: CGRectMake(0.0f, 48.0f, 320.0f, 100.0f)];
        [textView setText:*"Ciao"];
    
        /* 新增一個主要的顯示View 大小跟視窗本身一樣大 */
    
        mainView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
    
        /* 將剛剛的TextView給加上去 所有的iPhone畫面你都可以想成用描圖紙畫圖    *\
        \* 所有的畫面都是用貼的一層一層貼上去的 所以這一行把TextView黏在主畫面上*/
    
        [mainView addSubview:textView];
    
        /* 設定視窗本身 然後把主畫面黏在視窗上面 */
    
        [window makeKeyAndVisible];
        [window addSubview: mainView];
    好啦我們要開始寫我們自己的東西啦

    一個離線地圖工具做的事情大致上是這樣:
    因為iPhone上頭的google Maps會從Google下載地圖資料(圖片)
    然後把地圖資料用資料庫的格式 存在 /var/mobile/Library/Cache/MapTiles/Maptiles.sqlitedb 這個檔案裡面
    將關於這個地圖的中心座標位置 還有是第幾層地圖 這些資料 存在/var/mobile/Library/Preferences/com.apple.Maps.plist 這個檔案裡面

    所以離線地圖應該是可以讓你透過PC上面的GMDL下載圖資
    然後用它幫助你切換多個地圖資料
    (Point在切換 跟 多個圖資 如果你只有一個地圖 那你大可直接用覆蓋的 或是用ilm2這個程式就好了)
    只不過FW 2.2之後圖資格式改變了 需要用工具修改 詳情請看這裡(俄文)
    這樣你就不必浪費iPhone上面的網路頻寬去下載圖資
    可以同時擁有多個地圖資料 並且可以執行切換

    好 現在目標出來了
    我們需要一個畫面來說明

    sorry 註解的部份我弄不出來
    請到flickr這邊看

    簡單來說
    要達到跟原來離線地圖OfflineMaps差不多的功能
    我們需要一個Window ,一個mainView,一個NavigationBar(就是上面的那條標題欄),一個TableView畫面,一個儲存要顯示資料的陣列

    所以更改過的HelloWorld.h大概是這樣
    代碼:
    #import <CoreFoundation/CoreFoundation.h>
    #import <Foundation/Foundation.h>
    #import <UIKit/UIWindow.h>
    #import <UIKit/UIKit.h>
    #import <UIKit/UIApplication.h>
    #import <UIKit/UITableView.h>
    #import <UIKit/UINavigationBar.h>
    #import <UIKit/UIView.h>
    #import <Foundation/NSFileManager.h>
    #import <UIKit/UIAlert.h>
    #import <Foundation/NSString.h>
    
    *interface HelloWorldApp : UIApplication <
    	UITableViewDataSource,
    	UITableViewDelegate
    > {
    	    UIView            *mainView;
    	    UIWindow *window;
    	    UITableView *table;
    	    UINavigationBar *navbar;
    	    //主要的資料陣列
    	    NSMutableArray *list;
    	
    }
    *end
    跟原本的很像 但是有點不一樣
    大致上就是多了一些import檔案 因為我們用到的東西比較多
    至於HelloWorld.m則需要比較大的變動

    剛開始仍然不變 我們的啟始點仍然在- (void) applicationDidFinishLaunching: (id) unused
    多出來的那些 大部分是牽涉到TableView的詳細表現

    首先我們先看到 - (void) applicationDidFinishLaunching: (id) unused 的內容
    代碼:
        //這邊大同小異
        window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        
        /* Create a main view */
        mainView = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
    
        //開始新增一個NavigationBar 並且把它黏上去
        navbar =  [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 64.0f)];
        [navbar setDelegate: self];
        [navbar pushNavigationItem:[[UINavigationItem alloc] initWithTitle: *"OfflineMaps"] animated : true];
        [mainView addSubview:navbar];
    
        //開始設計我們的內容 把表單起始化
        list = [[NSMutableArray alloc] init];
    	for ( int i = 0; i<4 ; i++) [list addObject:[[NSMutableArray alloc] init]];
            // 這邊分成四個區塊 
    	// 0 => Maps
    	// 1 => Routes
    	// 2 => BookMarks
    	// 3 => Info
    	
        // 這是用來記錄讀進來的檔案的陣列
        NSMutableArray *maps = [[NSMutableArray alloc] init];
        // Objective-C讀取檔案用的工具 你可以想成 一個檔案總管
        NSFileManager *manager = [NSFileManager defaultManager];
        // Objective-C讀取檔案夾裡面的檔案是透過 NSString 字串的傳遞 這點還滿有趣的
        // 將一個路徑的字串交給 manager 他會把內容物丟到maps這個陣列裡面去
        // stringWithFormat:是讓你用一個模版來輸出字串 %[at]用後面 , 的字串取代
        // 很抱歉 因為論壇系統會擋掉小老鼠[at] 所以詳細的內容還是看source code好了
    
        [maps addObjectsFromArray:[manager contentsOfDirectoryAtPath:[NSString stringWithFormat:*"%[at]/Media/Maps", NSHomeDirectory()] error:NULL]];
        for (NSString *path in maps) {
            //確認一下這個檔案是不是資料夾 這下面的程式碼是從 Apple Developer的Reference抄來的...
    		BOOL isDir;
    		if ([manager fileExistsAtPath: [NSString stringWithFormat:*"/var/mobile/Media/Maps/%*",path] isDirectory: &isDir ] && isDir){
    			// 如果這個檔案是資料夾 那麼就在辨別 底下是否存在該存在的檔案
    			NSString *folder = [NSString stringWithFormat:*"/var/mobile/Media/Maps/%*",path];
    			if([manager fileExistsAtPath:[NSString stringWithFormat:*"%*/MapTiles.sqlitedb",folder]]){
    			// 好啦 看起來是 那就把這個檔案加入Map那一個區塊
    				[[list objectAtIndex: 0 ] addObject: path];
                            // 這邊就是Objective-C最特別的地方 用不完的中括號
    			}
    		}
    		else{
    			
    			// 如果不是資料夾 那麼他也許是路徑檔 或者是書籤檔
    			NSLog(*"Checking Bookmark or Routes"); 
                            // 這是輸出除錯的資料 不過 我自己是很不會看 log 
                            // 底下這段是用來辨別檔案是 Route或是BookMark的
                            // 也許有更漂亮的寫法 但是 我也是新手 我只追求可行
    			NSDictionary * plist = [NSMutableDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:*"/var/mobile/Media/Maps/%*",path]];
    			NSString *description = [plist description];
                            
                            //辨別 檔案開頭第六個字元開始的九個字元 形成的字串是
    			NSString *checker = [description substringWithRange: NSMakeRange(6,9)];
    			// detecting bookmark or Route
    			if ([checker isEqualToString:*"Bookmarks"])
    			{	//如果是書籤 就加入書籤這一塊
    				[[list objectAtIndex: 2] addObject: path];
    			}
    			else
    			{      //如果不是書籤 就加入路徑這一塊
    				[[list objectAtIndex: 1] addObject: path];
    			}
    		}
        }
            //加上一些細部功能
    	if([[list objectAtIndex:0] count] != 0){
    		[[list objectAtIndex:0] addObject: *"Remove Cache"];
    	}
    	if([[list objectAtIndex:1] count] != 0){
    		[[list objectAtIndex:1] addObject: *"Remove Route"];
    	}
    	if([[list objectAtIndex:2] count] != 0){
    		[[list objectAtIndex:2] addObject: *"Remove Bookmark"];
    	}
    	[[list objectAtIndex:3] addObject: *"Instruction"];
    	
    	table = [[UITableView alloc] initWithFrame:CGRectMake(0.0f,60.0f,320.0f,420.0f) style: 1];
    	// 1 代表 以群組區分的表單 0 代表 平面的表單
    	[mainView addSubview: table];
    	[table setDataSource:self];
            [table setDelegate:self];
    
        [table setEditing:NO animated:NO];
        table.allowsSelectionDuringEditing = YES;
    
        [table setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
        /* Setup window */
        [window makeKeyAndVisible];
        [window addSubview: mainView];
    至於其他function 有包括TableView的那些林林總總 則是規範表單的呈現方式
    這個部分我就建議大家去看看iPhone Develop Reference 有關 UITableView的部份了
    打算怎麼呈現表單的形狀 方式 有很多變化 大家可以發揮創意來操作
    當一切都完成了
    大家可以在/var/root/HelloWorld目錄下面
    執行 make ; make install
    然後重開機 看看結果

    當然詳細的程式還有許多需要改的地方
    這篇只是一個記錄 以免我年老忘記自己寫的步驟
    Google大神雖然可以告訴我們很多事情
    但是有些給的答案太多 有些又不是我們要的 所以 不寫下來真的以後會忘記
    附上的檔案裡頭的code有些有加上註解 有些則忘記了 XD
    大家有問題可以一起討論 ... 如果有些更好的寫法也請教我 謝謝


  2. #2
    alan 的頭像

    海盜船長

    註冊日期:10-24-2007
    文章:140
    謝謝你: 0
    在 0篇文章中獲得 0個感謝
    拜讀了.......
    感謝mask大的分享阿


  3. #3
    childk 的頭像

    愛用者

    註冊日期:02-20-2008
    文章:70
    謝謝你: 0
    在 0篇文章中獲得 0個感謝
    希望台灣搞 iPhone 程序的越來越多

    寫的很詳細,一定要拍拍手

    加油!加油!


  4. #4
    mask 的頭像

    管理團隊

    註冊日期:10-13-2007
    文章:285
    謝謝你: 4
    在 3篇文章中獲得 3個感謝
    這是簡單的Toolchain on 3.0的作法
    這邊下載最下面的附件
    把附件打開
    把Makefile裡的iphone ip換掉,程式的名稱換掉
    再用自己的source code替換掉Classes裡的檔案
    make ; make install
    就可以了

    有時候會因為header file不見了產生錯誤。
    用舊的dump class也許可以解決問題…


 

 

發文規則

  • 不可以發表新主題
  • 不可以發表回覆
  • 不可以上傳附件
  • 不可以編輯自己的文章
  •  
回到此頁頂端