2011年9月28日 星期三

[AndroidSign] apk sign

* Restriction
  • Android 系統禁止更新安裝簽名不一致的 APK。
  • You cannot release your application to the public when signed with the debug certificate.


* Generate apk sign
  • 要簽名一個沒有簽名過的APK,可以使用一個叫作 Auto-sign 的工具。
    • Auto-sign工具實際執行的是一個叫做Sign.bat的批處理命令。
    • 用文本編輯器開啟這個批處理文件。
  • Obtain a suitable private key


* signapk.jar
  • 是 Android 源碼包中的一個簽名工具。路徑為/build/tools/signapk/SignApk.java
  • 對比一個沒有簽名的 APK 和一個簽名好的 APK,會發現,簽名好的 APK 包中多了一個叫做 META-INF 的文件夾。裡面有三個文件:
    • MANIFEST.MF
    • CERT.SF
    • CERT.RSA。
  • signapk.jar 就是生成了這幾個文件(其他文件沒有任何改變。因此我們可以很容易去掉原有簽名訊息)。


* signapk.jar process:

1、生成 MANIFEST.MF 文件
  • 程式遍歷 apk 包中的所有文件(entry),對非文件夾非簽名文件的文件,逐個生成SHA1 的數字簽名訊息,再用 Base64 進行編碼。
  • 之後將生成的簽名寫入 MANIFEST.MF 文件。
  • SHA1 數字簽名
    • 是一種安全 hash 算法,類似於 MD5 算法。它把任意長度的輸入,通過散列算法變成固定長度的輸出(這裡我們稱作「摘要訊息」)。
    • 你不能僅通過這 個摘要訊息復原原來的訊息。另外,它保證不同訊息的摘要訊息彼此不同。
    • 因此,如果你改變了 apk 包中的文件,那麼在 apk 安裝校驗時,改變後的文件摘要信息與 MANIFEST.MF 的檢驗訊息不同,於是程式就不能成功安裝。

2、生成 CERT.SF 文件
  • 對前一步生成的 Manifest,使用 SHA1-RSA 算法,用私鑰進行簽名
  • RSA 是一種非對稱加密算法。
    • 用私鑰通過RSA算法對摘要訊息進行加密。在安裝時只能使用公鑰才能解密它。
    • 解密之後,將它與未加密的摘要訊息進行對比,如果相符,則表明內容沒有被異常修改

3、生成 CERT.RSA 文件
  • CERT.RSA文件中保存了公鑰、所採用的加密算法等訊息。


* Overview
1、 Android 簽名機制其實是對 APK 包完整性和發佈機構唯一性的一種校驗機制。
2、 Android 簽名機制不能阻止 APK 包被修改,但修改後的再簽名無法與原先的簽名保持一致。(擁有私鑰的情況除外)。
3、 APK 包加密的公鑰就打包在 APK 包內,且不同的私鑰對應不同的公鑰。換句話言之,不同的私鑰簽名的APK公鑰也必不相同。所以我們可以根據公鑰的對比,來判斷私鑰是否一致。


* APK Parser
  • 源碼中有一個隱藏的類用於APK 包的解析。這個類叫 PackageParser
  • 路徑為 frameworks\base\core\java\android\content\pm\PackageParser.java
  • 當我們需要獲取APK包的相關訊息時,可以直接使用這個 class。

我們就可以通過 packageInfo.signatures 來訪問到APK的簽名訊息。

它們的關係如下面代碼所示:

也就是說 signature = new Signature(certificate.getEncoded());

certificate 證書中包含了公鑰和證書的其他基本訊息。

公鑰不同,證書肯定互不相同。

我們可以通過 certificate 的 getPublicKey 方法獲取公鑰訊息。

所以比對簽名證書本質上就是比對公鑰訊息



Related
[Android] Debug Key


* Reference
- Android APK簽名對比及說明 - Android 軟體設計 - Android 台灣中文網 - Android(安卓,安致)討論區 - APK.TW **
- Signing Your Applications

[AndroidIntent] Intent Filter note

對一個android的應用程式而言,最重要的檔案是AndroidManifest.xml。它負責向下一層的framwork註冊該應用程式,包括此應用程式的名字,分組 (哪個category),用哪個icon,有什麼功能 (avtivity,service,broadcast receiver,content provider)等等。使得framework (package manager)接到通知 (intent)時,能夠根據目前系統註冊的情況,濾出符合條件的功能。


* Definition
  • Android 系統如何判斷哪個元件可以接收哪個 intent, 宣告在 AndroidManifest.xml 中。
  • 宣告元件時可加入的 Intent Filter 設定,屬性有 action, category, data,三個在一組內皆能有多個,只要符合三個各自條件,即通過此 intent-filter
  • 每個元件內可以設定 0 ~ 多組 的 intent filter每一組的 Intent Filter 都是一份比對規則,只要通過一組即可


* Process
當 intent 發出來時,系統會去檢查Manifest 內各元件內的intent filter, 而啟動適合的元件,若元件沒有設定filter,那就只能接收到有清楚指定 component 的 intent。


* action: 執行 intent 的方式。
  • 能有 0 ~ 多個
  • 合格條件: intent 中的 action 為 intent-filter 宣告的之一。
    • 如果沒有宣告任何一個,因為 intent 沒得比對,所以沒有任何 intent 會符合;
    • 如果是 intent 沒有帶有 action,filter 中至少有宣告一個,即能通過此 filter。

* category: intent 的類別。
  • 能有 0 ~ 多個
  • 合格條件: intent-filter 中必須完全符合 intent 中的 category
    • intent-filter 宣告比 intent 中還多的 category 是不影響的。
    • i.e. intent 中沒有 category,即合格。
  • Default Category
    • 當執行 startActivity() 而使用沒有明確設定目標的 intent (implicit intent),Category 會預設為 Intent.CATEGORY_DEFAULT
    • 因此,若 componen 需要接收 implicit intent,就必須在 intent filter 裡加上"android.intent.category.DEFAULT"。
    • 例外中的例外: 如果 filter 設定 "android.intent.action.MAIN" 和 "android.intent.category.LAUNCHER",則不需指定 DEFAULT 也可接收 implicit intent。

* data: intent 的資料類型。
  • 能有 0 ~ 多個
  • 合格條件: intent 中的 data 為 intent-filter 宣告的之一


. Updated on 2014/02/18


* Reference
- Android Intent Filter-判斷intent傳遞對象 - kei chueng - 博客园
- Intent Filter
- android -- 應用程式自我介紹之intent resolution @ 心的距離 :: 痞客邦 PIXNET ::
- <action>
- <category>
- <data>

2011年9月27日 星期二

[AndroidDev] Android Developers Blog: Preparing for Handsets



* Above code support  your app’s screen-size only for tablet in two different ways:
  1. It declares that the app does not support the screen size buckets “small”, “normal”, and “large”, which are traditionally not tablets
  2. It declares that the app requires a screen size with a minimum usable area that is at least 600dp wide

requiresSmallestWidthDp attribute is the new API supported from Android 3.2.

* The safest thing to do is develop your app against the platform that matches the API level you’ve set for minSdkVersion.

* For more information about why the “smallest width” screen size is important for supporting different screen sizes, read New Tools for Managing Screen Sizes (really; it’s got lots of things you need to know).

* Here are two guidelines to help make your Honeycomb tablet app work well on handsets:
  1. Build your design around Fragments that you can reuse in different combinations, in single-pane layouts on handsets and multi-pane layouts on tablets
  2. Be conservative with your Action Bar design so the system can adjust its layout based on the screen size

* Creating single-pane and multi-pane layouts
  • Single activity: Swapping the fragments within the activity when necessary.
    • Dynamically add each fragment to the activity at runtime---rather than declare the fragments in your activity’s layout file — because you cannot remove a fragment from an activity if it’s been declared in the XML layout.
  • Use separate activities to host each fragment on a handset.
    • When you need to switch fragments (such as when the user selects an item), start another activity that hosts the other fragment.


* Specifically, you should follow two general guidelines:
  • Do not manipulate one fragment directly from another.
    • To avoid directly calling one fragment from another, declare a callback interface in each fragment class that it can use to deliver events to its host activity, which implements the callback interface. When the activity receives a callback due to an event (such as the user selecting a list item), it acts appropriately based on the current fragment configuration.
  • Keep all code that concerns content in a fragment inside that fragment, rather than putting it in the host activity’s code.


* Here are some important tips:
  • When setting a menu item to be an action item, avoid using the “always” value. Use “ifRoom” for action items you’d like to add to the action bar. 
    • Now, you might need “always” when an action view does not have an alternative action for the overflow menu or when a menu item added by a fragment is low in the menu order and it must jump into the action bar at all times. But you should not use “always” more than once or twice.
  • When possible, provide icons for all action items and declare showAsAction="ifRoom|withText"
    • This way, if there’s not enough room for the text, but there is enough for the icon, then just the icon may be used.
  • Avoid using custom navigation modes in the action bar. Use the built-in tab and drop-down navigation modes.
    • They’re designed to be flexible and adapt to different screen sizes. 
    • For example, when the width is too narrow for both tabs and other action items, the tabs appear below the action bar. If your app requires a custom navigation mode in the action bar, thoroughly test it on smaller screens when Ice Cream Sandwich becomes available and make any adjustments necessary for a narrow action bar.


* Some other tips
  • When working with a ListView, consider how you might provide more or less information in each list item based on the available space. That is, you can create alternative layouts to be used by the items in your list adapter such that a large screen might display more detail for each item.
  • Create alternative resource files for values such as integers, dimensions, and even booleans. Using size qualifiers for these resources, you can easily apply different layout sizes, font sizes, or enable/disable features based on the current screen size.



* Reference
- Android Developers Blog: Preparing for Handsets

[Android] Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag

Error Message

Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

(發生在 content provider 中開啟 activity 時?)


Solution

Android has 4 components: Activity, Service, ContentProvider and Broadcast.

When Android needs to activate one of this components from your application, it looks if there is already existing running process with your application.

If not, then Android starts new process, initializes it, then it initializes your custom Application instance. And then it activates one of needed components.



Now, let's consider next scenario:

your application declared content provider in AndroidManifest.xml, and Android just about to start your application so you can provide some data to another foreground application.
and Android just about to start your application so you can provide some data to another foreground application.
Content Provider request is sent

  1. Your application wasn't running, and Android starts new process for it.
  2. Your custom Application instance is created
  3. Application.onCreate() is called.
  4. You start an activity
  5. Your Content Provider receives request

Somebody just wanted to connect to your content provider, but your application started an Activity instead. Same true for starting background Service and sometimes broadcast receivers.

Activity entends Context, and Override startActivity(). 如果使用 activity 中的 startActivity(),不會有任何限制,而如果使用 Context 的 startActivity(),就必須是在另一個新的 task. (?)

That's because you need to start new task when Activity is started outside of Activity context. But I strongly recommend to not start Activity from your Application'sonCreate().

Because Android guarantees that Application will be created only once and before any other component


* Reference
- startActivity的requires new task异常解析 - Android - mobile - ITeye论坛
- Android Application vs Activity - Stack Overflow **

[AndroidStorage] Content Provider 圖解







* Reference
- Byron's blog - Android 数据操作(个解)

2011年9月24日 星期六

[WEB] Project resources deployment path

ant > webroot /resources

maven > src/main/resources

[Android] app name setting and showing location

* When new an android project, you will see these information needed to fill:
  • Project name
    • 顯示在 eclipse 中的專案名稱。
    • export 時的預設名稱。
  • Application name
    • strings.xml 中預設產生的 app_name 的名稱。
    • activity 和 應用程式的預設名稱。
  • Package name
    • 預設產生的專案hierarchy。
    • AndroidManifest 中預設的 package name identifier.
    • BUT!
      • package hierarchy does not have directly relationship with package identifier. (?)
      • package identifier is relative to R.

* 在安裝 app 時,在 android installer 中的顯示名稱
  • 預設是使用<application>中的 label
  • 若沒有指定時,則是用 package name



* debug key apk cannot used to publish your app.

[Struts] <s:url>


<s:url>

會自動在 url 前加入 context root

2011年9月23日 星期五

[Android] Content Provider between Threads?

Error Message

java.lang.UnsupportedOperationException: Only CrossProcessCursor cursors are supported across process for now...



Solution

發生在 content provider 呼叫另一 content provider 的情況下

原因待解

20110923
- matrixCursor
- crossprocesscursor
- call content provider in another thread

[Apache] Set context root by MatchExPression

* Setting Apache context root (/conf/httpd.conf):

加入以下設定並填入該環境的 domain 和 port

MatchExpression /mobile WebLogicCluster={#domain}:{#port}|Debug=ON

[IE] focus

Error Message

在 IE6 和 IE7 上

若想要同時 focus 在頁面上和 alert 訊息

會因為先 alert 出訊息 而當使用者關掉 alert 再回到頁面上時

focus 效果已經消失 使用者也因此不會看到



Solution

利用 setTimeout( ) 來延遲 focus 事件 好讓使用者來得及看見

[WEBLOGIC] SAX Parser Factory


if [ "${SERVER_NAME}" = "managed01d-6" ] || [ "${SERVER_NAME}" = "managed01d-4" ]; then
    JAVA_OPTIONS="${JAVA_OPTIONS} -Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
    export JAVA_OPTIONS
fi

#
# http://forums.oracle.com/forums/thread.jspa?threadID=911954&tstart=150
# A bug with default SAX Parser Factory, version 10.3 for Windows
#
# JAVA_OPTIONS="${JAVA_OPTIONS}"
JAVA_OPTIONS="${JAVA_OPTIONS} -Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
export JAVA_OPTIONS








[JPA] javax.persistence.spi.PersistenceUnitInfo.getValidationMode()Ljavax/persistence/ValidationMode

Error Message
nested exception is java.lang.NoSuchMethodError: javax.persistence.spi.PersistenceUnitInfo.getValidationMode()Ljavax/persistence/ValidationMode;
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)


Solution

weblogic  /bea/setDomainEnv.sh 未指定 JPA jar path


if [ "${SERVER_NAME}" = "managed01d-1" ] ; then
    PRE_CLASSPATH="${DOMAIN_HOME}/lib-ext/hibernate-jpa-2.0-api-1.0.0.Final.jar"
    export PRE_CLASSPATH
fi

2011年9月19日 星期一

[Linux] crontab

* Definition
  • Linux/Unix 系統中用來讓系統各使用者自行設定在需要的時間 ,做需要的事的程式。
  • crontab 這個指令所設定的工作將會循環的一直進行下去! 除了可以使用指令執行外,亦可編輯 /etc/crontab 來支援。
  • 讓 crontab 可以生效的服務則是 crond 這個服務。
  • 若只需處理僅執行一次就結束排程的指令,可用 at

* 一般 Linux 在開機時會自動載入,如果發現無 crond 在跑,可以到 /etc/rc.d/ 目錄下看看是否有將執行crond 程式的指令加入開機自動執行檔裡面。


* User Name -> crontab file name
  • 當使用者使用 crontab 這個指令來建立工作排程之後,該項工作就會被紀錄到 /var/spool/cron/ 裡面去了,而且是以帳號來作為判別的。
  • 所有使用者的 crontab 檔都會存檔 /usr/spool/cron/crontab/ 下,每個人都只有一個檔案存在,檔名就是該帳號的名字。ex:
    • dmtsai 使用 crontab 後, 他的工作會被紀錄到 /var/spool/cron/dmtsai

[Note] 不要使用 vi 直接編輯該檔案, 因為可能由於輸入語法錯誤,會導致無法執行 cron 。

* cron 執行的每一項工作都會被紀錄到 /var/log/cron 這個登錄檔中。

* Re-start /etc/init.d/crond restar
在 Linux 底下的 crontab 會自動的幫我們每分鐘重新讀取一次 /etc/crontab 的例行工作事項,但是某些原因或者是其他的 Unix 系統中,由於 crontab 是讀到記憶體當中的,所以在你修改完 /etc/crontab 之後,可能並不會馬上執行, 這個時候請重新啟動 crond 這個服務吧!『/etc/init.d/crond restart』。


* syntax:
#crontab [-u username] [-l|-e|-r]

/*
選項與參數:
-u : 只有 root 才能進行這個任務,亦即幫其他使用者建立/移除 crontab 工作排程;
-e : 編輯 crontab 的工作內容
-l  : 查閱 crontab 的工作內容
-r : 移除所有的 crontab 的工作內容,若僅要移除一項,請用 -e 去編輯。
*/


[Note]
  • 如果只是要刪除某個 crontab 的工作項目,那麼請使用 crontab -e 來重新編輯即可!』如果使用 -r 的參數,是會將所有的 crontab 資料內容都刪掉的。
  • 使用者可以用 crontab -e 指令來編寫需要做的工作或者將要執行的工作,或寫在一個 file 裡,再執行 crontab filename 就可以了。
  • 注意必須使用 絕對路徑。

ex:
// 此時會進入 vi 的編輯畫面讓您編輯工作,然後以一個工作一行來編輯,
// 編輯完畢之後輸入『 :wq 』儲存後離開 vi 就可以了。
#crontab -e


* 每項工作 (每行) 的格式都是具有六個欄位,如下:
(minute) (hour) (day of month) (month) (day of week) (job)

* 每欄位可填入的值如下:

  • minute: 0-59
  • hour: 0-23
  • day of month: 1-31
  • month: 1-12 (or names, see below)
  • day of week: 0-7 (0 or 7 is Sun, or use names),週的數字為 0 或 7 時,都代表『星期天』的意思。


ex:
# 每小時的 5,15,25,35,45,55 分
5,15,25,35,45,55 * * * * (job)

# 每個小時 10 分
1 * * * *  (job)

 # 每天早上三點整
0 3 * * * (job)

# 每個月一號早上 3:50
50 3 1 * * (job)

# 每週日早上 4:30
30 4 * * 0 (job)

# 每週六早上 5:30
30 5 * * 6 (job)



* 特殊符號
  • 星號(*)
    • 代表任何時刻都接受。
    • ex: 0 12 * * * (job)
      • 日、月、週都是 * , 就代表著『不論何月、何日的禮拜幾的 12:00 都執行後續指令』的意思。
  • 逗號(,)
    • 代表分隔時段的意思。
    • ex: 0 3,6 * * * command
      • 要下達的工作是 3:00 與 6:00,第二欄是 3,6 ,代表 3 與 6 都適用 。
  • 減號(-)
    • 代表一段時間範圍內。
    • ex: 20 8-12 * * * command
      • 8 點到 12 點之間的每小時的 20 分都進行一項工作,第二欄變成 8-12 ,代表 8,9,10,11,12 都適用的意思。
  • 斜線(/n)
    • n 代表數字,亦即是『每隔 n 單位間隔』。
    • ex: */5 * * * * command
      • 每五分鐘進行一次,也可以寫成 0-59/5 ,相同意思。


[Note]
週與日月不可同時並存,
30 12 11 9 5 root echo "just test" <==這是錯誤的寫法


* 進行登錄檔的輪替 (log rotate):
  • Linux 會主動的將系統所發生的各種資訊都記錄下來,這就是登錄檔。 
  • 由於系統會一直記錄登錄資訊,所以登錄檔將會越來越大。
  • 我們知道大型檔案不但佔容量還會造成讀寫效能的困擾, 因此適時的將登錄檔資料挪一挪,讓舊的資料與新的資料分別存放,則比較可以有效的記錄登錄資訊。這就是 log rotate 的任務!這也是系統必要的例行任務。



* Reference
- 鳥哥的 Linux 私房菜 -- 例行性工作排程的建立 ***
- Crontab 的寫法(@reboot, @yearly...) | Tsung's Blog
- crontab 使用格式說明 **

2011年9月18日 星期日

[WEB] Tile, JSTL, JS syntax in HTML





${status.count}


 colspan="2">



* Tile 的 attribute 在 HTML 中可透過 getAttribute 取得,ex:

<tiles:insertAttribute name="title" />





* 視 js 為 .txt