-
toolchain版本的離線地圖
這邊要討論的是如何從別人的程式改起 變成自己的東西
站在巨人的肩膀 總是比自己單搞看的遠
(其實是我根本沒辦法從頭開始寫一個程式 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上面的網路頻寬去下載圖資
可以同時擁有多個地圖資料 並且可以執行切換
好 現在目標出來了
我們需要一個畫面來說明
http://farm4.static.flickr.com/3022/...480358c8_o.png
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則需要比較大的變動
http://farm4.static.flickr.com/3081/...2d564d43_o.png
剛開始仍然不變 我們的啟始點仍然在- (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
大家有問題可以一起討論 ... 如果有些更好的寫法也請教我 謝謝
-
拜讀了.......
感謝mask大的分享阿(跪拜禮new)
-
(GOODJOB) 希望台灣搞 iPhone 程序的越來越多
寫的很詳細,一定要拍拍手(跪拜禮new)
加油!加油!
-
底下是記錄…
這是簡單的Toolchain on 3.0的作法
到這邊下載最下面的附件
把附件打開
把Makefile裡的iphone ip換掉,程式的名稱換掉
再用自己的source code替換掉Classes裡的檔案
make ; make install
就可以了
有時候會因為header file不見了產生錯誤。
用舊的dump class也許可以解決問題…