[Android] 全自動覆蓋安裝APK

好吧,連自己都覺得這個Script很方便
簡單來說這可以
1. 如果機器有曾經有安裝過,會自動執行解除安裝
2. 自動安裝新版APK
3. 自動打開剛裝好的APK (如果有需要)

使用方式很簡單

./ReInstallAPK.sh myApp.apk

如果需要自動打開,就加上 start 字樣

./ReInstallAPK.sh myApp.apk start

就這樣

需要設定 ANDROID_HOME 環境變數,目前只能用USB接一台Android devices
有空可以把它改成一次發佈多台的

https://gist.github.com/j796160836/df2dbf05d9f408739c06

[Android] 如何做到多重螢幕支援 (Multi Screen Support) (1/2)

這個主題不是很好寫,也不是很好解釋
我儘量把我所知道的解釋出來,如果有誤請糾正

在Android的世界裡,螢幕非常多

4" 5" 6" 7" 8" 9" ….各種寸數都有
其中也有各種解析度

 

但在使用者的眼中,只有 手機、平板 這二種類別

至少在iOS的世界是這樣子分的沒錯(只分iPhone / iPad二種版)

(正確應該說是三種版,因為iPhone5之後它變長了)


有些名詞要先懂

Density

到時候一定會圍繞這個單字,字面意思是 密度

這裡要表示螢幕上的密度

 

PPI (Pixel per inch)

字面翻譯爲 一英寸多少像素

算數公式如下:

tumblr_lxiqrxwFxp1qjgx8i  

實際算法可以從畢氏定理求得知

螢幕寬平方 與 螢幕高平方 相加後 開根號  得到一個值
然後將這個值除以螢幕對角線實際尺寸的值

跟我們常聽到的DPI (Dot per inch)想法很像

 

都是螢幕對角線的 虛擬尺寸(px)實際尺寸(inch) 的 比值
表示一種密度

 

小螢幕畫質很精密,這代表著他的密度很高

iPhone的Retina螢幕也是在表示這件事 


再來你需要知道Android對於像素的處理

Density-independent pixel (dp)

也簡稱為 dip 或 dp

Android他就發明了這個詞,這代表一個單位 (可以度量的單位,可以將它當做是layout使用的px)

這個單位的發明,只為了解決一件事情

不管螢幕密度多少,都要在實際畫面 (可以直接拿皮尺量螢幕的尺寸,例如:公分)  呈現一樣大的大小

在正確一點來說

不管螢幕密度為何,都以160dpi所看到螢幕的看到的差不多大(這句看不懂沒有關係)

 

 

放張大家有印象的圖

density-test-bad  

若是在螢幕尺寸不變(假設爲4"手機螢幕),由左至右 爲 低畫質 至 高畫質
螢幕就像640×480 演變成 1024×768 再演變成 1920×1080的感覺一樣

以前字很大,隨著解析度條高,字也就越小(畫面也就更細緻了)

因為密度變大了

density-test-good  

若使用了dp這個單位的話,就算是螢幕再細緻,畫面實際尺寸也不會有太大的差異

這就是Android想要達成的目的,就算是比較差的手機(畫質差),至比較高檔的手機(高畫質)

畫面也不要差太多

 

dp 轉 px 的公式如下

px = dp * (dpi / 160)

公式搬移一下變成

dp = px / dpi * 160

 

這時候就出現了ldpi、mdpi、hdpi、xhpi 這幾個詞,這個跟圖有關係,晚點再解釋


螢幕的分類

這個就是重點了

Android對於螢幕的分類有以下:

Small、Normal、Large、XLarge

這幾種

就跟你穿衣服一樣
不是有S號、M號、L號、XL號嗎?

這就是螢幕的大小

Android官方這裡有一張一般螢幕尺寸與密度的對照圖

screens-ranges  

這張對於螢幕尺寸(第一行)的部分,只有給區間而已

你不需要去拘泥與這張圖的分類  到底是幾吋到幾吋,也不需要急著要知道你手上的這支手機的型號 是 屬於哪個分類

這張圖的重點只有 一個

也就是

平板 都常都落在 large 以上


重點是你需要知道

螢幕分類dp 之間的關係

因為各家螢幕大小不一樣,這裡有列一個參考值

xlarge screens are at least 960dp x 720dp
large screens are at least 640dp x 480dp
normal screens are at least 470dp x 320dp
small screens are at least 426dp x 320dp

它幫我們算出,每個分類 至少 會有多少dp

當然參考值畢竟是參考值,多少會有例外
例外的部分就依照個別機種去調整版面

 

就我的經驗是

你必須要先考慮各種螢幕大小的版型是否會跑版,
再來考慮圖的畫質問題

 

怎麼測各種螢幕大小、機種?有幾種方法

  1.  儘可能的拿實機測

  2.  拿模擬器,指定特定的密度與螢幕大小來模擬

 

剛建立版型的時候,先固定一種螢幕大小去測試 (例如手上測試機)

然後先利用GenyMotion等模擬器,把所有螢幕大小分類都跑一遍
有問題的話先做修正

再來就是看各機種的問題做測試了


密度的分類

再來是畫質密度的問題,就是文章開頭很頭痛 Density

密度的分類剛剛看過了

ldpi、mdpi、hdpi、xhpi

screens-densities  

一樣有low、medium、high、extra high等分別

以mdpi為基準點

3:4:6:8比例做縮放

 

以48px x 48px的圖示來說

ldpi 為 36×36

mdpi 為 48×48 (因為它是基準點嘛) 

hdpi 為 72×72

xdpi 為 96×96

 

以Desire HD來說

device-2014-02-18-014336  

(不要再問我為何Desire HD有4.0.3了,因為我有刷機嘛)

以Desire HD來說,像素尺寸為 480×800

分類屬於 normal / hdpi 的螢幕

所以是換算成mdpi的話,將px全部除上1.5倍

480 / 1.5 = 320
800 / 1.5 = 533.33

再回頭查看原有程式的比例

在dp這一欄,剛好就是320×533

 

 

官方文件可以清楚看到

ldpi Resources for low-density (ldpi) screens (~120dpi).
mdpi Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
hdpi Resources for high-density (hdpi) screens (~240dpi).
xhdpi Resources for extra high-density (xhdpi) screens (~320dpi).
tvdpi Resources for screens somewhere between mdpi and hdpi; approximately 213dpi. This is not considered a “primary” density group. It is mostly intended for televisions and most apps shouldn’t need it—providing mdpi and hdpi resources is sufficient for most apps and the system will scale them as appropriate. If you find it necessary to provide tvdpi resources, you should size them at a factor of 1.33*mdpi. For example, a 100px x 100px image for mdpi screens should be 133px x 133px for tvdpi.

ldpi 約爲 120dpi,mdpi 約為 160,hdpi 約為 240,xhdpi 約為 320

dpi的數字你不知道是多少也沒關係,可以直接記住 3:4:6:8 的比例(或是圖片上的 0.75x、1x、1.5x、2x 也行)


tvdpi

比較特別的是tvdpi,約為213dpi,這個專為電視所設計,因為電視現今螢幕不管多大尺寸通常都是 1920×1080

而且不管上述螢幕尺寸一致的問題,就是固定是倍率大小為1.33x

這跟使用體驗有關,畢竟電視不是像手機一樣般的操控

 

 


 

大部份的資料,參考自這份很難懂的原文資料

http://developer.android.com/guide/practices/screens_support.html

我很少把參考資料的字放大(代表它很重要),多看幾次才會知道它在寫什麼 

 


 

參考資料:

http://en.wikipedia.org/wiki/Pixel_density

http://shareandopen.tumblr.com/post/15559202965/android-support-multiple-screens

http://developer.android.com/training/multiscreen/screensizes.html

[.Net / C#] 撰寫在背景執行的服務 (Windows Service)

最近在研究Windows Service

網路資料有些片段,寫個文章整理一下

 

主要目標很簡單,就是寫一個排程器

每隔幾秒做事情

放在伺服器上

—–

以下用visual studio 2012做示範

 

建立專案

一樣老樣子從開新專案開始

File -> New -> Project…

Screen Shot 2014-02-03 at 7.09.57 PM  

選Visual C# -> Windows -> Windows Service   (中文叫做Windows服務)

然後打上專案名稱 (這裡用MyService1)

按下OK後建立

Screen Shot 2014-02-03 at 7.10.18 PM  

然後就建立專案

Screen Shot 2014-02-03 at 7.51.03 PM  

這裡可以發現這個Service的專案跟一般視窗專案有些不同

除了一樣有Program.cs

多了Service1.cs

點選Service1.cs在Design模式時,什麼都沒有(因為只有元件沒有畫面)

點選Click here to switch to code view直接看程式碼

Screen Shot 2014-02-03 at 7.11.28 PM  

這裡就有原始碼

Screen Shot 2014-02-03 at 7.55.37 PM    

只有很簡單的OnStart跟OnStop

因為它是服務,所以無法直接執行

直接按Start按鈕執行的話會看到這個視窗

Screen Shot 2014-02-03 at 7.12.25 PM  

意思是說,這服務需要被安裝才可以執行

需要用到 installutil.exe 這程式來安裝(等下再介紹)
然後還要用NET START指令啟動服務(這可以不用理會沒關係,我們可以用圖形介面)

———

到這裡還沒有開始寫排程器,還要爲這個服務做一些設定

回到Service1.cs的Design模式(就是剛剛什麼都沒有地方)

按右鍵 -> Add Installer (加入安裝程式)

Screen Shot 2014-02-03 at 8.01.11 PM  

這時會多一個ProjectInstaller.cs檔案,在設計模式底下會有這二個東西

Screen Shot 2014-02-03 at 8.05.49 PM  

點選 serviceInstaller1

Screen Shot 2014-02-03 at 8.08.00 PM  

這裡需要做一些設定

DisplayName 就是服務要顯示的名稱

Description 服務描述

ServiceName 服務的唯一名稱

StartType 啓動方式,初始值爲Manual (手動)
當然要設定Automatic (自動) 呀

DelayedAutoStart 爲開機之後是否延遲啓動

 

點選 serviceProcessInstaller1

Screen Shot 2014-02-03 at 8.13.38 PM  

設定只要改一個

Account 這裡決定服務的帳號與權限

我們可以設定爲LocalSystem (就是最大權限)

———

 

撰寫相關程式碼

先撰寫定時器

這裡用到 System.Timers 所以要先引用

using System.Timers;

 

然後寫一個定時器

private Timer MyTimer;

public Service1()

{

    InitializeComponent();

}

 

protected override void OnStart(string[] args)

{

    MyTimer = new Timer();

    MyTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);

    MyTimer.Interval = 10 * 1000;

    MyTimer.Start();

}

 

private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)

{

    // Do SomeThing…

}

 

這裡設定 定時器為每10秒 執行一次

 

日誌輸出

在設計模式拉一個EventLog

Screen Shot 2014-02-03 at 8.55.57 PM  

然後增加一些程式碼變成如下

private Timer MyTimer;

 

public Service1()

{

    InitializeComponent();

    this.AutoLog = false;

    if (!System.Diagnostics.EventLog.SourceExists(“MySource”))

    {

        System.Diagnostics.EventLog.CreateEventSource(

            “MySource”, “MyLog”);

    }

    eventLog1.Source = “MySource”;

}

 

protected override void OnStart(string[] args)

{

    eventLog1.WriteEntry(“Start Timer.”);

    MyTimer = new Timer();

    MyTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);

    MyTimer.Interval = 10 * 1000;

    MyTimer.Start();

}

 

private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)

{

    eventLog1.WriteEntry(“Timer Ticked.”);

}

 

protected override void OnStop()

{

    eventLog1.WriteEntry(“Stop Timer.”);

    MyTimer.Stop();

    MyTimer = null;

}

 

 

剩下就讓大家自由發揮了

——————————

安裝 / 解除安裝 服務

 

剛剛不是有提到 installutil.exe 嗎?

官方文件是寫

安裝服務的時候執行指令

InstallUtil MyService1.exe

解除安裝的時候執行指令

InstallUtil /u MyService1.exe

但事情沒有這麼簡單

 

installutil.exe 它其實是在

C:WindowsMicrosoft.NETFramework<版本號>   底下

Screen Shot 2014-02-03 at 7.13.05 PM  

版本號會有很多個

因為我這個專案是用.Net Framework 4.5

所以就用v4.0.30319

有安裝.Net Framework 4.5都會有這個資料夾,也會有這個程式

但還有一個問題

因為我執行時是用LocalSystem

這個需要額外的管理員權限

——-

在這裡我寫了二個Bat檔案,做安裝服務與解除安裝的服務

這裡只列安裝服務,反正把指令加上 /u 就是 解除安裝就不列出了

Install-MyService1.bat

內容為 

@ECHO OFF

net session >nul 2>&1
IF NOT %ERRORLEVEL% EQU 0 (
   ECHO ERROR: Please run Bat as Administrator.
   PAUSE
   EXIT /B 1
)

@SETLOCAL enableextensions
@CD /d “%~dp0”

REM The following directory is for .NET 4
SET DOTNETFX4=%SystemRoot%Microsoft.NETFrameworkv4.0.30319
SET PATH=%PATH%;%DOTNETFX4%

ECHO Installing MyService1…
ECHO —————————————————
InstallUtil /i .MyService1.exe
ECHO —————————————————
ECHO Done.
PAUSE

 

藍色字自行修改所需要的.Net版本號
還有服務程式的exe名稱

橘色字是檢查管理員權限用的
若Account不是選LocalSystem的話

可以刪掉它

——————————

執行測試

完成之後可以做安裝,然後做測試

在Install-MyService1.bat按右鍵 -> Run as administrator

Screen Shot 2014-02-03 at 9.16.09 PM   

打開控制台 -> 系統管理工具 -> 服務

這個列表裡面就會多了一個你的服務

Screen Shot 2014-02-03 at 9.24.25 PM

裡面的名稱都跟剛剛打的一樣

 Screen Shot 2014-02-03 at 9.24.41 PM  

 

那我們剛剛寫的日誌呢?

控制台 -> 系統管理工具 -> 事件檢視器

找到Applications and Services (應用程式及服務記錄檔)

就會多出一個MyLog

裡面就是我們寫的日誌檔

Screen Shot 2014-02-03 at 9.29.35 PM  

 

除錯

之前在重複若干次的 安裝服務/解除安裝服務 的時候

有遇到EventLog的問題

可以嘗試去登錄編輯器(regedit)刪除以下機碼

HKEY_LOCAL_MACHINESYSTEMControlSet001serviceseventlogMySource
HKEY_LOCAL_MACHINESYSTEMControlSet001servicesMySource
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetserviceseventlogMySource
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesMySource

在執行 解除安裝服務 的程式

 

參考資料:

http://blog.wahahajk.com/2008/06/cservice.html
http://msdn.microsoft.com/en-us/library/y817hyb6(v=vs.110).aspx
http://gogo1119.pixnet.net/blog/post/27575780-%5Bc%23%5D-windows-service%E5%BB%BA%E7%AB%8B%E7%AF%84%E4%BE%8B
http://www.cnblogs.com/xianspace/archive/2009/04/05/1429835.html

http://stackoverflow.com/questions/3307151/receiving-has-already-been-registered-from-eventlog-createeventsource-ev
http://stackoverflow.com/questions/4824051/problem-installing-windows-service

 

[MySQL] 增加phpmyadmin的登入過期時間

有時候需要因為測試用途,需要把phpmyadmin的Token過期時間加長
省得要一直反覆登入的麻煩

在phpmyadmin資料夾底下的config.inc.php

增加或修改這行

$cfg[‘LoginCookieValidity’] = 3600 * 9; // 9 小時

 

在Mac底下的XAMPP可以用這指令修改

sudo vi /Applications/XAMPP/xamppfiles/phpmyadmin/config.inc.php

 

參考資料:

http://stackoverflow.com/questions/4361416/phpmyadmin-configuration

[PHP] PHP 5.4 (for Windows)之後版本連接Microsoft SQL Server

Screen Shot 2013-08-26 at 12.50.45 PM  

PHP要怎麼連Microsoft SQL Server?網路上教學很多

但很多是舊版,這是新版的做法
只有Windows平台受影響

 

敝人愛用XAMPP所以就用這套講起

它好像自從其中一個版號之後…
XAMPP for Windows把原本mssql的連接方式抽掉了

只能用Native Client的連接方式

 

而其它平台則不受影響


簡單講一下差異…

Screen Shot 2013-08-26 at 8.28.07 PM  

這裡有三個流程圖…

Mac / Linux 是看最右邊的方式,底層採用FreeTDS連接SQL Server

Windows則有二種方式連接,中間的是舊版做法,左邊的是新版做法

 

簡單來說…就是換Library了啦!

SQLSRV的話,是微軟提供&維護的Driver,

 

在Microsoft官網有完整的API Reference
http://msdn.microsoft.com/en-us/library/cc296152.aspx

當然,php官方也Mirror了一份

http://php.net/manual/en/book.sqlsrv.php

 

所以這篇,主要教怎做這個更換Library的動作

 

 


剛開始,你在Configure Command裡面看到類似 "–without-mssql" "–without-pdo-mssql"的字眼就不要太緊張

因為它換模組名稱

 


敝人愛用XAMPP所以就用這套講起

首先你需要裝一個Native Client

依照這個網址指示
http://msdn.microsoft.com/en-us/library/cc296170.aspx

Screen Shot 2013-08-26 at 1.08.39 PM  

這就看你的SQL Server版本不同平台不同裝不一樣的

 

我的話,用Microsoft SQL Server 2008,系統是64位元的
所以裝這個

http://go.microsoft.com/fwlink/?LinkID=188401&clcid=0x409

(它有特別提到,系統如果是64位元的SQL Server就一定要裝64位元的)


到這網址

http://www.microsoft.com/en-us/download/details.aspx?id=20098

抓檔案 

 

但這也要看PHP版本,以我的版本XAMPP 1.8.2 for Windows來說

Screen Shot 2013-08-26 at 1.16.48 PM  

我的圖面上很清楚看到的是php 5.4

然後比照php資料夾裡的dll是Thread Safe 還是 non-Thread Safe的版本

 

Screen Shot 2013-08-26 at 1.11.14 PM  

 

 

以我的版本XAMPP 1.8.2 for Windows來說

我在C:xamppphp裡面

找不到php5.dll但有php5ts.dll

所以我知道我的版本是Thread Safe版本

SQLSRV30.EXE檔案,用7-zip等程式直接解壓縮(本身執行檔是壞的,不用在雙點了)

就會得到

php_sqlsrv_54_ts.dll

php_pdo_sqlsrv_54_ts.dll

這二個檔案

 

把它複製到C:xamppphpext 裡面

然後手動在php.ini裡面加上

extension=php_sqlsrv_54_ts.dll

extension=php_pdo_sqlsrv_54_ts.dll

然後重開Apache

—————–

看phpinfo(),找sqlsrv就會看到類似以下畫面

Screen Shot 2013-08-26 at 12.49.33 PM  

就完成了

 

因為模組有變更,程式碼也變更

所以以下這段在Windows底下就棄用了喔(Mac / Linux的話不受影響,還是用這一段)

<?php
$conn = mssql_connect($serverName, $DBUsername, $DBPassword)
or die("Couldn’t connect to SQL Server on $myServer");
if (!$conn) {
die(‘Something went wrong while connecting to MSSQL’);
}
?>

 

改成新版的寫法 

<?php
$serverName = "localhost"; //serverNameinstanceName
$connectionInfo = array( "Database"=>"dbName", "UID"=>"userName", "PWD"=>"password");
$conn = sqlsrv_connect( $serverName, $connectionInfo);

if( $conn ) {
echo "Connection established.<br />";
}else{
echo "Connection could not be established.<br />";
die( print_r( sqlsrv_errors(), true));
}
?>


網路找了個半天,終於解出來問題了

之後來測試一下連線

 

至於更詳細sqlsrv和mssql使用上的差異

可以參考這一篇

http://blogs.msdn.com/b/brian_swan/archive/2010/03/10/mssql-vs-sqlsrv-what-s-the-difference-part-2.aspx

 


參考資料:

整個模組Reference

http://php.net/manual/en/book.sqlsrv.php
http://msdn.microsoft.com/en-us/library/cc296152.aspx

安裝準備

http://msdn.microsoft.com/en-us/library/cc296170.aspx

官方的範例

http://msdn.microsoft.com/en-us/library/cc296196(v=sql.105).aspx

 

http://blogs.msdn.com/b/brian_swan/archive/2010/03/08/mssql-vs-sqlsrv-what-s-the-difference-part-1.aspx
http://blogs.msdn.com/b/brian_swan/archive/2010/03/10/mssql-vs-sqlsrv-what-s-the-difference-part-2.as

http://www.apachefriends.org/f/viewtopic.php?f=16&t=49670&p=191610&hilit=SQLSRV#p191610

 

[iOS] Apple iOS Developer Program 開發者帳號 申請實錄

Screen Shot 2013-07-08 at 1.24.24 AM  

話說 iOS開發者帳號已經想申請想很久了

最近心一橫,拿出信用卡
就給它刷下去了

 

但是…申請過程沒有那麼順利(我申請了二次)

所以就把一些東西記錄下來,給大家參考


敗家 阿不是,是學習大門的網址都幫你準備好了:

https://developer.apple.com/programs/ios/

看到 iOS Developer Program

的藍色Enroll Now的按鈕,就用力的給他點下去吧!

Screen Shot 2013-07-08 at 1.26.26 AM  

這裡有大概跟你說整個申請流程
簡單來說選擇1. 申請身份 2. 填資料 3. 線上刷卡及人工審核
直接按Continue繼續

 

Screen Shot 2013-07-08 at 1.29.05 AM  

 

 

申請新的Apple ID

 

這裡說要登入Apple ID,或是新創一個Apple ID帳號去綁開發者帳號

我是選Create Apple ID去新創一個Apple ID

到這裡都還算簡單

Screen Shot 2013-07-08 at 1.32.16 AM  

 

然後就是填Apple ID的資料…資料都要真實的
因為到時候Apple那邊會查

Screen Shot 2013-07-08 at 1.33.40 AM  

這裡請特別注意…Middle Name請不要雞婆的去填寫它,乾脆說請直接忽視Middle Name的欄位

台灣人不需要這個欄位

只要依照指示填寫First Name姓氏,Last Name名字,就好

Screen Shot 2013-07-08 at 1.38.29 AM  

至於地址的部份,我當時是寫英文啦

只是Preferred Language是填Chinese就是了

送出之後呢…就創立一個 Apple ID了


但還沒完,還沒有填到重點的部份

 

 

開發者帳號申請

Screen Shot 2013-07-08 at 1.43.12 AM  

它會問你,你要申請哪種開發者帳號

Individual (個人) 還是Company/Organization (公司)

Company的部分我個人沒申請過…

我是選擇 Individual


Screen Shot 2013-07-08 at 1.48.46 AM  

看到很多黃色區塊了吧?這幾步非常的重要

它說,這個名字一定要是你信用卡申請人的名字

所以像圖上的範例就是

意思就是說….不能用他人的信用卡代刷這筆費用

而且這名字一定要是你的真名

而且還有一個重點,

申請送出了之後(包含錢),資料就無法做修改

所以要特別特別的填清楚

當然,Middle Name的欄位請略過…台灣人不需要這個欄位

至於填中文還是英文,Apple客服說都可以

 

但一定要讓他們對得到資料

Screen Shot 2013-07-08 at 1.57.01 AM  

地址欄位欄位也是,送出後無法修改
我就不贅述了

Screen Shot 2013-07-08 at 2.02.45 AM  

資料確認頁,確定無誤就按下一步
再次提醒你,這裡的Name打上的是Johnny Sung是

你必須要打上你的真名

Screen Shot 2013-07-08 at 2.04.17 AM  

Apple授權協議頁,他很貼心的給你PDF的版本
按 I Agree繼續

Screen Shot 2013-07-08 at 2.06.34 AM  

頁面會幫你轉到Apple Store的商店

加入iOS Developer Program這個項目到你的購物車裡

 

Screen Shot 2013-07-08 at 2.06.56 AM  

這邊有沒有覺得很神奇,突然什麼都變成中文了

我想可能是Preferred Language是填Chinese的關係

按下「結帳」繼續

 

Screen Shot 2013-07-08 at 2.07.50 AM  

直接按下「繼續」

Screen Shot 2013-07-08 at 2.08.09 AM

這邊很神奇,它又要你填一次地址

這次沒得選,只能填中文(它的表單有設計過,你填英文會不夠長)

我想這個欄位應該是沒有使用到

Screen Shot 2013-07-08 at 2.09.18 AM  

這裡就很重要了,要你填入信用卡的卡號 安全碼等等的資料

請容許我在重述一次

這個名字一定要跟你剛剛填的申請人名字一樣

所以….不能用他人的信用卡代刷這筆費用

而且這名字一定要是你的真名

申請送出了之後(包含錢),資料就無法做修改

按下「繼續」之後

按下同意授權條款就結束了


你的信箱會收到一封類似這樣的信

Screen Shot 2013-07-08 at 2.23.04 AM  

能幹嘛呢?只有等…還是等…

 

Screen Shot 2013-07-08 at 2.28.27 AM  

大概在24小時之內,會收到一封啓動序號的信

Screen Shot 2013-07-08 at 2.30.57 AM  

順著啓動序號的連結會來到這個網頁

按下Activate鍵就會啓動…


你認為這麼簡單嗎?別高興太早

那個按鈕,就算你是用合法的序號也是會被擋下來的

因為他有人工驗證的部份,人工驗證沒過
一切都白搭

 

如果你有看我文章(?),很細心的注意每個步驟和表單

你就會收到這個成功信件

Screen Shot 2013-07-08 at 2.39.02 AM  

這封信的大意是說,我們已經對過你提供的資料,並移除了擋板

你只要在重新到啓動碼頁面  點一下就會啓用開發者帳號了

 

=========================================

 

 

 

退換貨處理

如果你像我一樣,資料沒有打對的話
要怎麼辦?

 

首先,你會收到類似這樣的信件

Screen Shot 2013-07-08 at 2.37.54 AM  

這段文字很讓人飆髒話,所以貼出來

In order for us to verify your identity, you need to upload a notarized or solicitor certified copy of your government issued photo identification.

就是說,你提供的資料不符,他要求你要上傳一個經過公證單位或律師(solicitor) 公證過的有照片的文件

 

這時候有FAQs 跟 Contact us可以選

Screen Shot 2013-07-08 at 3.11.30 AM  

 

我當下直接選了Call us

https://developer.apple.com/contact/phone.php

Screen Shot 2013-07-08 at 3.18.00 AM   

直接找台灣的電話打就行了,還好是0800免付費電話

跟客服講你現在的情況,還有跟他說你的Apple ID

他就會把原因告訴你

 

打電話了之後,你現在只有二個選項:

  1. 乖乖的去把你的證件拿去公證單位公證然後上傳我是沒有去公證過啦,據網路上查詢的結果 

    根據外交部領事事務局的網頁
    http://www.boca.gov.tw/content?mp=1&CuItem=4990
    倘國、內外要證機關無特別規定要求護照影本須先經國內地方法院公證處或民間公證人證明,申請人可直接向本局或本部中部、南部、東部、雲嘉南四辦事處申辦出具中華民國護照影本與正本相符之證明。 

    蓋個章,規費 $400

    若真的要公證,需要到 台北地院公證處
    http://lawtw.com/article.php?template=article_content&area=free_browse&parent_path=,1,655,7,&job_id=82850&article_category_id=1965&article_id=36859
    中文 $500元,英文 $750元

    根據Apple客服的說法,雙證件也不行
    送出的資料也不能讓使用者或是客服修改資料後重新驗證
    比郵局開戶還難,這點真的會讓人家氣炸

  2. 把這筆申請(包含錢),通通退掉,再重來一次

我是選擇這個選項,他們會照著你的要求做,寄送紙本發票和
折讓單(SAS FORM)到你府上

 

 

你要填一些資料然後簽字寄回去給Apple

Screen Shot 2013-07-08 at 9.27.47 AM  

 


過了幾天之後就會收到這個

LastScan2-2  

統一發票

LastScan-2  

所謂的折讓單(SAS FORM)….上面有個又愛又恨的蘋果

 

這裡我就不重述了,簽一簽,寄回去

然後又是等….


你可以當下拿出信用卡,再刷一次

再走一次這樣的流程

有這麻煩到家的流程,所以一再的提醒你

別打錯字

 

 

折騰了老半天,最後還是申請出來了

大概花了4天吧

這種麻煩事,要走過才會知道有多麻煩
貼出來讓大家更瞭解這機車的流程

有很多地方要注意的點

 

之後我來筆記帳號開通之後能做的事情

謝謝收看。

[Mac/Linux] 在Mac使用usb轉RS232 (serial port / com port)

RS232是什麼?不解釋。
要的話自己去買一條
http://shopping.pchome.com.tw/?mod=store&func=style_show&SR_NO=DCAC16

===以下給有需要的人使用===

驅動部份找這家的晶片

http://www.prolific.com.tw

像我找到這個驅動
http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=229&pcid=41
Screen Shot 2013-01-22 at 2.21.39 PM  

md_PL2303_MacOSX10.6_dmg_v1.4.0.zip

下載解壓縮,安裝完會重新開機

然後打開Applications > Utilities > Terminal (或是你喜愛的Terminal程式)

使用screen指令

screen /dev/cu.usbserial 115200

這個cu.XXXXXX可能會不一樣,我這邊是 cu.usbserial
(這個要安裝完驅動才有唷)
115200就是baud rate

這時會在現有的Terminal執行另一個「視窗」
字面解釋是視窗沒錯,應該說是文字模式下的多工(就像你在切換tty一樣)

到了screen模式底下,可以按control + A 加上 ?
看看help

—–

如果要結束這個對話框
請先按control + A 再按 control + \

(Linux 的話就是Ctrl + A 再按 Ctrl + \ )

如果不離開的話,這個serial可是會被佔用的喔

後來研究一下screen這個指令
其實還蠻好玩的

推薦看這篇

http://wiki.shsh.ylc.edu.tw/index.php/Screen

screen模式下按Ctrl + A 然後 D
儲存現有狀態
然後用screen -r 指令叫回來

Ctrl + A 然後 C 開新的「視窗」
也可以Ctrl + A 連按二次做視窗間切換

 

 

資料來源

http://www.mobile01.com/topicdetail.php?f=482&t=446370&p=1

http://www.rackaid.com/resources/linux-screen-tutorial-and-how-to/

http://wiki.shsh.ylc.edu.tw/index.php/Screen

 

http://pbxbook.com/other/mac-tty.html

http://forums.macrumors.com/showthread.php?t=1125800

 

[Android] 安裝NDK與使用JNI呼叫系統底層native的C/C++程式 (Java call C)

因為工作需要,所以在這做個筆記
也順便學習一下

JNI全名叫Java Native Interface,意思就是說
這不是Android獨有的東西,純Java的應用程式也可以寫
(但本例還是以Android下的JNI為主)

以下是用Mac去搭建的,同樣的做法Linux也可以

 

環境準備

假設你已經有開發過Android的經驗

有Android  SDK+Eclipse最基礎的環境

這樣你需要加裝NDK(Native Development Kit) 和CDT(C/C++ Development Toolkit)

首先,先到Android官網下載NDK,解壓縮後存在一個路徑

下載網址:

http://developer.android.com/tools/sdk/ndk/index.html

像本例用Mac搭建,所以下載Mac版本

 

在Help > Install New Software 就像是你之前在安裝Android的環境一樣

Screen Shot 2013-01-15 at 5.54.38 PM  

但我們是要安裝CDT,這裡小小的不一樣

Work with:這欄打入

http://download.eclipse.org/tools/cdt/releases/indigo

然後勾選CDT Main Features安裝C/C++開發環境

Screen Shot 2013-01-15 at 6.03.51 PM  

接下來就是Next大法,沒啥好解釋的

Screen Shot 2013-01-15 at 6.04.54 PM  Screen Shot 2013-01-15 at 6.05.11 PM  

按下Finish,馬上就開始下載了

Screen Shot 2013-01-15 at 6.06.12 PM  

安裝完成的訊息問你要不要重開Eclipse,就照預設值Restart Now

Screen Shot 2013-01-15 at 6.11.25 PM  

但還沒完,

Eclipse重開了以後,再次Install New Software回到這個畫面

這次填上ADT的網址

https://dl-ssl.google.com/android/eclipse/

這次勾選NDK Plugins

Screen Shot 2013-01-15 at 6.14.40 PM  

剩下那些廢圖我就不重覆貼了

CDT和NDK安裝只多了一個警示框,按OK繼續安裝

Screen Shot 2013-01-15 at 6.17.38 PM  

Eclipse再次重開之後,在Eclipse > Preferences視窗中 

Screen Shot 2013-01-16 at 8.55.38 AM   

Android > NDK的頁籤中

選取你下載解壓後的NDK路徑
我是把它跟android sdk放在一起,有必要的話可以參考我的路徑

 Screen Shot 2013-01-16 at 8.55.24 AM  

環境設定完,就馬上開始寫程式摟!

新增專案

就像是老樣子,New > Android Project,開啟一個Android專案
因為這裡講到爛掉,所以我跳快一點

Screen Shot 2013-01-16 at 9.03.08 AM  

我開了一個專案

Application Name: HelloNDK
Package Name: com.J_Test.hellondk

Activity Name: MainActivity
Layout Name: activity_main

加入JNI支援

這裡就跟一般的Android專案不一樣

在你的專案按下右鍵 > Android Tools > Add Native Support…

Screen Shot 2013-01-16 at 9.07.37 AM  

出現一個視窗
提示你JNI編譯輸出的名稱

Screen Shot 2013-01-16 at 9.13.00 AM  

按下Finish之後,會發現你的專案目錄多了Includes和jni資料夾這二項

Screen Shot 2013-01-16 at 9.20.29 AM

 

設計JNI函數名稱 

HelloNDK.cpp和Android.mk是我們今天編輯的重點

首先,先將HelloNDK.cpp 重新命名為 HelloNDK.c

然後編輯Android.mk

LOCAL_PATH := $(call my-dir)

 

include$(CLEAR_VARS)

 

LOCAL_MODULE    := HelloNDK

LOCAL_SRC_FILES := HelloNDK.c

 

include$(BUILD_SHARED_LIBRARY)

這個HelloNDK和HelloNDK.cpp,就是先前填寫.so的名稱 
將檔名改成對應的名稱

 

我們在MainActivity加入以下:

static

{

     System.loadLibrary("HelloNDK");

} 

public native String helloString();

public native int plus(int a, int b);

public native int multiply(int a, int b);

 

把我們要呼叫C使用的方法界面,加個native修飾字
此例

helloString()  回傳一個測試字串

int plus(int a, int b)  做兩數相加

int multiply(int a, int b)  做兩數相乘

最後加上System.loadLibrary 載入我們即將要自定的JNI Module Name

 

產生Header檔案

我們用javah指令產生JNI對應的Header file
但它會讀取編譯後的*.class檔案

所以在這之前,請將專案整個Build過一遍

請先確定專案下的bin/classes+package名稱的對應之資料夾
是否有編譯後的*.class檔(這在Eclipse專案目錄下不會看見,用Finder去開)

本例是HelloNDK/bin/classes/com/J_Test/hellondk/MainActivity.class

 

接下來,打開Terminal

切換到專案的根目錄

使用這個指令

javah -d jni -classpath bin/classes <package名稱+class名稱

在本例就是

javah -d jni -classpath bin/classes com.J_Test.hellondk.MainActivity 

順利執行之後,回到Eclipse,專案視窗按F5重新整理

在jni資料夾會多出com_J_Test_hellondk_MainActivity.h這個檔,內容為以下

/* DO NOT EDIT THIS FILE – it is machine generated */

#include<jni.h>

/* Header for class com_J_Test_hellondk_MainActivity */

 

#ifndef _Included_com_J_Test_hellondk_MainActivity

#define _Included_com_J_Test_hellondk_MainActivity

#ifdef __cplusplus

extern“C” {

#endif

/*

 * Class:     com_J_Test_hellondk_MainActivity

 * Method:    helloString

 * Signature: ()Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_com_J_1Test_hellondk_MainActivity_helloString

  (JNIEnv *, jobject);

 

/*

 * Class:     com_J_Test_hellondk_MainActivity

 * Method:    multiply

 * Signature: (II)I

 */

JNIEXPORT jint JNICALL Java_com_J_1Test_hellondk_MainActivity_multiply

  (JNIEnv *, jobject, jint, jint);

 

#ifdef __cplusplus

}

#endif

#endif

好吧,我承認它是真的醜了點
但還是可以寫C程式的 

想想當初怎麼寫C程式,一個標頭檔…只宣告參數型別
但沒宣告參數名稱

 

實作JNI

編輯HelloNDK.c內容

#include<jni.h>

#include<string.h>

 

#include“com_J_Test_hellondk_MainActivity.h”

 

JNIEXPORT jstring JNICALL Java_com_J_1Test_hellondk_MainActivity_helloString(

JNIEnv *env, jobject thiz) {

   return (*env)->NewStringUTF(env, “Hello from JNI !”);

}

 

JNIEXPORT jint JNICALL Java_com_J_1Test_hellondk_MainActivity_multiply(

JNIEnv *env, jobject thiz, jint a, jint b) {

   jint total = 0;

   total = a * b;

   return total;

}

先不管JNIEXPORTJNICALL等關鍵字

jintjobjectjstring等型別,這些是Java裡給的型別

這裡有張對照表

Java型別 型別表示 字節大小(bit)
boolean jboolean 8, unsigned
byte jbyte 8
char jchar 16, unsigned
short jshort 16
int jint 32
long jlong 64
float jfloat 32
double jdouble 64
void void

至於String、物件、陣列…等,處理起來就較複雜些


疑難排解

在編譯時我有遇到

Method ‘NewStringUTF’ could not be resolved 

 

解決辦法,

在專案下按右鍵  Properties >C/C++ General > Paths and Symbols 的頁籤中

按下Add…選擇

<ndk路徑>/platforms/android-14/arch-arm/usr/include

/Users/johnny/android-sdks/android-ndk/platforms/android-14/arch-arm/usr/include

就可以解決

Screen Shot 2013-01-17 at 2.58.43 AM  

若在使用javah遇到類似的訊息

error: cannot access com.J_Test.hellondk.MainActivity
class file for com.J_Test.hellondk.MainActivity not found
javadoc: error – Class com.J_Test.hellondk.MainActivity not found.
Error: No classes were specified on the command line. Try -help.

請先確定*.class的位置

不含package的資料夾路徑

要從專案裡的bin資料夾,或是bin/classes資料夾尋找

若沒有,請重新編譯一次(輸出一次到模擬器是個不錯的選擇)


最後,感謝這些參考資料,都是來自世界各個角落的精華
讓我好好學了一課!

device-2013-01-17-023803  

對了,有了function name,要寫個測試程式應該不難吧
這種艱巨的任務,就交給你了!(笑)

 

 

參考資料: 

http://androidcookbook.com/Recipe.seam?recipeId=77

http://changyy.pixnet.net/blog/post/29469121
http://changyy.pixnet.net/blog/post/29437517

http://developer.android.com/training/articles/perf-jni.html

http://87showmin.blogspot.tw/2009/06/java-java-native-interfacejni.html

https://github.com/androidcook/Android-Cookbook-Examples/tree/master/NdkDemo

http://java.chinaitlab.com/JDK/36678.html

http://blog.csdn.net/ljlsunny/article/details/5753006

http://electrofriends.com/qna/jni-faq/convert-jstring-cstyle-string-vice-versa/

http://blog.csdn.net/gavinr/article/details/7343324

[Android] 要學會的關鍵技術—XML的讀取(3)

device-2012-03-23-142254

系列文章:

[Android] 要學會的關鍵技術—XML的讀取(1) 

[Android] 要學會的關鍵技術—XML的讀取(2) 

[Android] 要學會的關鍵技術—XML的讀取(3)

 


講完技術性的東西之後,最後就是把它設定起來

 

版面檔 main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

 

    <TextView

        android:id="@+id/textView1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="讀取RSS新聞標題:" />

 

    <LinearLayout

        android:id="@+id/linearLayout1"

        android:layout_width="match_parent"

        android:layout_height="wrap_content" >

 

        <EditText

            android:id="@+id/trg_url"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_weight="1"

            android:hint="請輸入RSS網址"

            android:text="http://tw.news.yahoo.com/rss/travel"

            android:singleLine="true">

 

            <requestFocus />

        </EditText>

 

        <Button

            android:id="@+id/get_data"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="取得" />

    </LinearLayout>

 

    <ScrollView

        android:layout_width="match_parent"

        android:layout_height="match_parent" >

 

        <TextView

            android:id="@+id/result_txt"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content" />

    </ScrollView>

 

</LinearLayout>

 

主程式 Main.java

 

package com.J_Test.XMLParserTest;

import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import com.J_Test.XMLParserTest.Module.SimpleXMLParser;
import com.J_Test.XMLParserTest.ParsingHandler.RssNewsXMLParsingHandler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
 

public class Main extends Activity implements OnClickListener

{

     private static final String TAG = “XMLParserTest”;

     /** 「要更新版面」的訊息代碼 */

     protected static final intREFRESH_DATA = 0x00000001;

     /** Rss資料的網址 */

     String trgUrl;

     /** 新聞資料的物件陣列 */

     RssNews[] Arr_RssNews;

     private Button getData_btn;
     private TextView result_edtxt;
     private EditText trgUrl_txt;

     /** 建立UI Thread使用的Handler,來接收其他Thread來的訊息 */

     Handler mHandler = new Handler()

     {

           @Override

           public void handleMessage(Message msg)

           {

                switch (msg.what)

                {

                // 更新資料,將Rss新聞的標題用迴圈依序印出來

                case REFRESH_DATA:

                     result_edtxt.setText(“”);

                     for (int i = 0; i < Arr_RssNews.length; i++)

                     {

                           result_edtxt.append(Arr_RssNews[i].getTitle() + “n”);

                     }

                     break;

                }

           }

     };

 

     /** Called when the activity is first created. */

     @Override

     public void onCreate(Bundle savedInstanceState)

     {

           super.onCreate(savedInstanceState);

           setContentView(R.layout.main);

           // 版面初始化

 

           getData_btn = (Button) findViewById(R.id.get_data);
           result_edtxt = (TextView) findViewById(R.id.result_txt);
           trgUrl_txt = (EditText) findViewById(R.id.trg_url);
           getData_btn.setOnClickListener(this);

     }

     @Override

     public void onClick(View v)

     {

           // 若是按下getData_btn的按鈕

           if (v == getData_btn)

           {

                // 擷取trgUrl_txt文字框裡的內容

                trgUrl = trgUrl_txt.getEditableText().toString();

                // 開一個執行緒(Thread)

                new Thread()

                {

                     @Override

                     public void run()

                     {

                           Arr_RssNews = getRssNews();

                           if (Arr_RssNews != null)

                                 // Handler上發出「要更新版面」的訊息

                                 mHandler.sendEmptyMessage(REFRESH_DATA);

                     }

                 }.start();

            }

      }

 

     /**
      * 從網路擷取RSS的資料(需要搭配執行緒)
      * @return Rss新聞的物件陣列
      */

     public RssNews[] getRssNews()

     {

           if (trgUrl == null)

                return null;

           try

           {

                // 建立一個Parser物件,並指定擷取規則 (ParsingHandler)

                SimpleXMLParser dataXMLParser = new SimpleXMLParser(

                new RssNewsXMLParsingHandler());

                // 呼叫getData方法取得物件陣列

                Object[] data = (Object[]) dataXMLParser.getData(trgUrl);

                if (data != null)

                {

                     // 如果資料形態正確,就回傳

                     if (data[0] instanceof RssNews[])

                     {

                           return (RssNews[]) data[0];

                     }

                }

           } catch (SAXException e)

           {

                e.printStackTrace();

           } catch (IOException e)

           {

                e.printStackTrace();

           } catch (ParserConfigurationException e)

           {

                e.printStackTrace();

           }

           // 若有錯誤則回傳null

           return null;

     }

}

 


呼….結束了。

什麼?你又忘了!

再給我忘記這句

<uses-permission android:name="android.permission.INTERNET" />

我就搥你

 

參數設定檔 AndroidManifest.xml

<?xml version=“1.0” encoding=“utf-8”?>

<manifest xmlns:android=“http://schemas.android.com/apk/res/android”

    package=“com.J_Test.XMLParserTest”

    android:versionCode=“1”

    android:versionName=“1.0” >

 

    <uses-sdk

        android:minSdkVersion=“8”

        android:targetSdkVersion=“17” />

    <uses-permission android:name=“android.permission.INTERNET” />

    <application

        android:allowBackup=“true”

        android:icon=“@drawable/ic_launcher”

        android:label=“@string/app_name”

        android:theme=“@style/AppTheme” >

        <activity

            android:name=“com.J_Test.XMLParserTest.Main”

            android:label=“@string/app_name” >

            <intent-filter>

                <action android:name=“android.intent.action.MAIN” />

                <category android:name=“android.intent.category.LAUNCHER” />

            </intent-filter>

        </activity>

    </application>

</manifest>