Tuesday, December 31, 2013

串接Admob時岀現The Google Play services resources were not found.

文章攢寫時間︰2013/12/31 17:45
Admob使用版本︰Goole Play Service 4.0版

一、問題

今天在串接Admob時,
遇到
The Google Play services resources were not found. Check your project configuration to ensure that the resources are included.
的錯誤,
Admob廣告一直沒有岀現。

二、解決辦法

請在values\strings.xml裡,
填上你的ad_unit_id...


Monday, December 30, 2013

Tapjoy與Proguard的親密接觸

文章攢寫時間︰2013/12/31 11:40

一、前言
話說等一下即將邁入2014年,
各位安卓猿們有沒有安排跨年計劃,
亦或待在家專心趕code呢?
先祝大家新的一年健康快樂、事業順利啊!

言歸正傳,
這幾天在寫code時,
遇到了Tapjoy在Proguard編譯岀來的apk檔裡發生的問題。

二、問題

為了不要讓Java檔一下子就被破解,
Android提供了Proguard工具。

這幾天在使用tapjoy機制時,
運行時遇到了因為程式Proguard後,
導致找不到tapjoy library resources的NullPointerException問題。

三、解決辦法

只要在proguard腳本檔(proguard-project.txt)裡添加兩行即可解決
-keep class com.tapjoy.** { *; }
-keepattributes JavascriptInterface

相關文章︰

Tuesday, October 29, 2013

IAB-V3使用經驗小記(陸續新增)

文章攢寫時間︰2013/10/29 15:45

Google Play in-app billing V3的使用經驗記錄於下︰
1.如果將應用程式內商品退費,短期內似乎不能再購買此商品(20131029觀察中)

Tuesday, September 24, 2013

[電影]賈伯斯 觀後感(無爆雷)

文章攢寫時間︰2013/09/25 10:42

「賈伯斯」好看嗎?

這是在看完電影「賈伯斯」特映會後,最多人問我的一句話。

它不是Local商業片,不像鋼鐵人3,不像大尾鱸鰻,不像總舖師,
它是一部描述一個人的傳奇、一個人一生的電影,
因此在劇本的設計上通常是不用太刻意製造笑點或哭點的,
只要忠實的陳述岀人、事、時、地、物和有故事核心,
就已經是傳記類故事合格的表達方式。

1)人 - 賈伯斯何許人也?
2)事 - 賈伯斯發生什麼事?
3)時 - 賈伯斯的經歷?
4)地 - 賈伯斯在哪裡創業、哪裡成功?
5)物 - 賈伯斯發明了些什麼改變了世界?

(文章看到這裡,連我都打了一聲哈欠)

如果電影裡的故事都是真實故事,
那麼依我看,
賈伯斯是一個『糟糕透了』的人。

賈伯斯他是為了事業,將最親愛的人不顧的人。
他是一個眼光狹獈至極不懂得分享成功的人。
他是為了一件事的成功,忽略了其它所有感受和看法的人。

成功有許多的方式、途徑,
絕對沒有哪一條路是對、是好,

他的執著、他的偏執、他的狂妄、他的理念,
他的「簡單、清楚、力與美學」的工業設計理念,
很多決策他必須要相信他自己、認同他自己,
而這條路,就像他的創業夥伴在離開他前哭著對他說︰
「我知道你是那麼地孤單。」


成功不是僥倖、不是運氣,
我看到的是他對於理念的執著、
一個科技企業人看事的遠光、
還有一顆永遠不安逸於現況的心。

這部戲不需要果粉才能看,
因為它是一部傳記,
描述了一個人成功的故事和一生。

沒有賈伯斯就沒有Apple,
沒有Apple就不會有Android,
因此,
賈伯斯不僅是Apple之父,
他也是Android之父、
更是智慧型手機之父。

不安逸於現況、永遠要比別人看地更遠、對一件認為是對的事情的堅持與執著⋯
這些想法都在我內心不斷地共鳴著。


這部戲不是Local商業片,
所以你絕對不會從你朋友口中聽到「賈伯斯超好看的,你趕快去看」這類的話。
因此片商也很聰明的直接在宣傳海報上打了一排字︰「歡迎企業包場。」


我最終還是流下了男兒淚,
一個成功的人,
一路上...真的...很孤獨。

Saturday, June 1, 2013

升級ADT22後專案開不了,報NoClassDefFoundError錯誤。

文章攢寫時間︰2013/06/01 19:04

一、問題

升級ADT到v.22後,
原本能開的專案突然開不了,
還報NoClassDefFoundError的紅字錯誤給我們看。

二、解決辦法

原來在v.22 Android團隊將專案會用到的libs再度收納到了Android Private Library,
所以需要將Android Private Library開起來。


Android Team的Andreas Stutz在他的G+好心的提醒我們升級到ADT 22會產生NoClassDefFoundError錯誤
更弔詭的是
還有網友說還要繼續把專案關起來再打開,
才能恢復正常...

附上操作流程︰
1.專案點擊右鍵
2.Build Path-> Configure Build Path -> Order and Export
3.選取Android Private Libraries方塊,並按OK
4.清除你的專案[Project]-->[Clean]
5.編譯你的專案

Saturday, May 25, 2013

Game Service串接注意事項(更新中)

文章攢寫時間︰2013/05/25 14:20

1.需要在Android Menifest.xml裡<application>和<activity>中間宣告
 

 
否則會遇到java.lang.IllegalStateException: A fatal developer error has occurred. Check the logs for further information. 的錯誤。

2.在values資料夾要放置ids.xml宣告你的app_id和成就以及排行榜相關的id

3.注意在Google Api Console的使用額度(quota)

Wednesday, May 22, 2013

Google I/O 2013 - Custom View筆記

文章攢寫時間︰2013/05/22 18:40

Google I/O 2013 - Custom View筆記

  1. View的繪製流程可以直接draw(),但也可以先onMeasure()再onLayout()再draw(),onMeasure()和onLayout()一定會是同步發生。
  2. 要客製化做出自已的View,一定是implements ViewGroup。
  3. ViewGroup不僅是一個容器,還是一個管理子View的控件。
  4. 客製View的第1個流程︰requestLayout() - 這個函式告訴系統你現在有一個View需要被計算和繪製。
  5. 把requestLayout()想成是一個草稿,在這個時間點你可以改變你的View大小、可以改變View在hierachy的層級⋯等等。
  6. 呼叫了requestLayout()後,對於整個View的層級影響是很大的,它可以影響到它的父視圖的計算、父父視圖的顯示⋯。
  7. 客製View的第2個流程︰實作onMeasure() - 用這個函式來決定你的View的大小,還有你這個View之後裝的子View的大小。
  8. onMeasure()是一個不斷循環的函式(recursive process)
  9. onMeasure()的責任是要去找出並量出子View的合適大小
  10. 量出View的大小的方法︰MeasureSpec
  11. MeasureSpec的第1種工具︰精確的指定大小(MeasureSpec.EXACTLY)
  12. MeasureSpec的第2種工具︰依子View的大小做判斷給出理想範圍(MeasureSpec.AT_MOST)
  13.  MeasureSpec的第3種工具︰不指定大小(MeasureSpec.UNSPECITIED),最常見的例子就是ScrollView和ListView。
  14. 客製View的第3個流桯︰onLayout() - 將你在onMeasure()裡定義好的大小,去計算所有子View即將存放的螢幕所在位置。
  15. ViewGroup專用的尺寸定義工具︰LayoutParams
  16. 如果沒有指定LayoutParams,如果你用的是FrameLayout,那麼系統會配予match_parent屬性。
  17. Drawing - Android的介面渲染工具。
  18. invalidate(),跟requestLayout()不同的地方在於,如果你的View有動畫、有變形...,可以使用這個函式來請求重繪。
  19. 使用Drawing渲染工具的方式 - 實作函式onDraw()
  20. 如果你的View都會由子View去繪圖,那麼就可以setWillNotDraw(true)讓系統去跳過onDraw()這個流程。
  21. dispatchDraw()被負責繪製子view,包含變形、動畫⋯等等的事件。
以上為聆聽筆記,如有誤煩請回應告知。

Monday, May 20, 2013

R檔不見了

R檔記錄了Android Project裡各種資源的位址,
是很重要的資料。
這份資料是自動產生的,
會存在於gen資料夾底下。

如果發現沒有R檔通常使用[Project]-->[Clean],
R檔都能回來。

如果仍然回不來,
請先確定res目錄底下的所有資源都沒問題了(沒有紅色xx),
再執行一次[Project]-->[Clean]。

R檔才會出現...

Monday, November 5, 2012

測量物件寬高

有時候在getWidth和getHeight無法起作用,
Romain Guy提到因為物件還沒畫出來,
因此此值會回傳0。

因同事的努力,
翻牆到有一位網友j研究了怎樣才會取到物件的寬和高。
用法是這樣的
  1.  final ImageView imageView = (ImageView) findViewById(R.id.imageview);        
  2.         
  3.       //------------------------------------------------方法一  
  4.       int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);  
  5.       int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);  
  6.       imageView.measure(w, h);  
  7.       int height =imageView.getMeasuredHeight();  
  8.       int width =imageView.getMeasuredWidth();  
  9.       textView.append("\n"+height+","+width);  
詳文請參見連結

Friday, September 7, 2012

ListView裡的OnItemClickListener失去作用(失效)

一、Problem
今天在實作ListView,自訂義一個Adapter繼承BaseAdapter後,
發現ListView原本的OnItemClickListener失去作用。

二、Description
上圖是ListView的其中一橫條,
為了讓內容豐富,
用了2個ImageView(圖片)和2個TextView(文字)元件。
有時候為了讓ListView的內容豐富,
我們常會自訂義一個Layout來讓ListView的內容多元,
但也因為多元,
如上圖所示,ImageView和TextView預設都有自己獲得Focus的能力,
這些元件搶走了原本List獲得焦點的能力。

每一條ListView在點擊時,
原本都擁有自己的Focus,
因此ListView的點擊才有效用。

如果我們希望List被點擊後,
讓OnItemClickListener仍有作用,
該怎麼做呢?

三、Solution
外國論譠描述要改善子元件不影響原來ListView獲得Focus最快的方式就是在自訂義的Layout中,附上一個屬性︰

下片這段程式碼就是上面List_Item內容的Layout佈局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/feeback_item_bg"
    android:gravity="center_vertical"
    android:descendantFocusability="blocksDescendants">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="3dp"
        android:layout_marginLeft="10dp"
        android:text="題編"
        android:textColor="#FFFFFF"
        android:textSize="8sp" />


    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/feedback_q" />

<TextView
        android:id="@+id/textView3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingBottom="5dp"
        android:singleLine="false"
        android:text="題目內容"
        android:textColor="#000000" />


    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/feedback_a" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:inputType="text|textMultiLine"
        android:paddingRight="20dp"
        android:text="答案"
        android:textColor="#000000" />

</LinearLayout>

如上面紅色標註,
Android有提供一個快捷方式讓Layout裡的子元件全部失焦,
就是使用
android:descendantFocusability="blocksDescendants"

註︰
1.當我在使用這個屬性時,
仍然無法讓OnItemClickListener發揮作用,
後來才發現我的TextView裡原本有設定一個屬性android:inputType="textMultiLine"
外國網友討論說這是一個Android的BUG,
此屬性一旦宣告,
又會讓上面紅色的宣告失去效果。
我把inputType="textMultiLine"拿掉,
整個問題才被解決。 
2.最好用RelativeLayout的方式,使用僅一層Layout的架構客製這個list_item,
不僅在滑動有效率,也不會有這篇產生的問題。

Saturday, September 1, 2012

在EC2發送Android推播產生中文亂碼

一、Problem
這幾天試驗在亞馬遜Amazon AMI(CentOS)上發送Android的GCM(推播系統)給用戶,
卻一直遇到手機收到中文亂碼的問題。

二、Solution
  1. 安裝中文字元集 yum install fonts-chinese
  2. 設定系統語系檔 #vi /etc/sysconfig/i18n LANG="en_US.UTF-8" 修改為 LANG="zh_TW.UTF-8"
  3. 重新開機

Wednesday, August 29, 2012

購買in-app billing,Google Play視窗開了2次

今天遇到一件事,
至從增加Subscription服務後,
Dungeons在request購買時,
畫面會先跳出找不到項目,
然後又跳出in-app billing商品列表,
I encountered a problem when I was using Google In-app billing today that is when I request purchase, Google Play Billiing view shows twice.
First, It shown "Can't find Item" dialog then shown me the in-app billing product item what I set.

爬文才發現問題出在Google Play Billing的Sample Code:Dungeons.java出了一個邏輯上的錯誤,
那就是︰
Finally I figure out the cause is logic in in-app billing sample code:Dungeons.java.
Wrong code is on below:


 @Override
    public void onClick(View v) {
        if (v == mBuyButton) {
            if (Consts.DEBUG) {
                Log.d(TAG, "buying: " + mItemName + " sku: " + mSku);
            }

            if (mManagedType != Managed.SUBSCRIPTION &&
                    !mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_INAPP, mPayloadContents)) {
                showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
            } else if (!mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_SUBSCRIPTION, mPayloadContents)) {
                // Note: mManagedType == Managed.SUBSCRIPTION
                showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
            }

        } else if (v == mEditPayloadButton) {
            showPayloadEditDialog();
        } else if (v == mEditSubscriptionsButton) {
            editSubscriptions();
        }
    }

紅色那段的邏輯錯誤,
造成Google Play視窗被開啟兩次,
只要將那段改成
 if (mManagedType != Managed.SUBSCRIPTION &&
                    !mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_INAPP, mPayloadContents)) {
                showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
            } else if (mManagedType == Managed.SUBSCRIPTION && !mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_SUBSCRIPTION, mPayloadContents)) {
                // Note: mManagedType == Managed.SUBSCRIPTION
                showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID);
            }
即可改善Billing視窗開了2次的問題。 
If modify code as above will fix this bug.

Friday, August 10, 2012

輸出時出現Dalvik的UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException

今天將isLibrary的專案Build出來時,
遇到一個
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lcom/xxx/sample/R$attr;
的錯誤,
結果在Library裡將bin目錄底下的com/xxx/sample/刪掉,
就能正常Build出程式了。

Monday, July 9, 2012

Fragment筆記

撰寫日期︰2012/07/09 16:55
修改時間︰2015/10/26 14:07
修改次數︰5
一、前言
Android在3.0時就已經推出了Fragment(片斷)這個元件,可惜因為Android3.0以上的市占一直不高,因此一直沒有很完整的使用範例,但是因為最近我在用兼容套件,它能幫我們在Android2.x就使用Fragment,我也剛好用到,順便在這裡把我的學習心得記錄下來。

二、文章開始

1.淺談Fragment
Fragment,它屬於一個完整的Activity使用介面的其中一部份,想像一下,我們可以將多個fragments放在一個Activity底下,達到多區塊的程式能在一個或多個Activity間彼此靈活運用、互相溝通。(可以把它看成是一個子Activity,它們可以在很多個不同的Activity中同複使用)。

Fragment必需被崁在Activity裡面,它的生命週期也完全受到Activity的影響。什麼意思呢?假設今天Activity被Destroy()掉了,Fragment也會跟著被Destroy()掉。
然而,如果Activity運行中,你可以針對Activity裡的數個Fragment做個別獨立的控制,像是新增一個個的Fragment,甚至是移除掉它們。
當你執行fragment transaction時,你還能夠將你新增的Fragment添進back stack(背景堆疊,請見我2010年寫的文章)這個被Activity管理的機制中。每個back stack寫入時機皆發生在fragment transaction發生的時間點上,back stack允許使用者使用手機的返回鍵返回fragment transaction的狀態。

當你新增了一個fragment到你的Activity Layout的同時,它就被常駐進Activity裡ViewGroup的View階層中,它們還能夠自訂義應該要擁有怎麼樣的Layout。
你可以在Activity的Layout中去定義Fragment的擺放位置(使用<fragment>這個tag標籤),當然,也可以使用coding的方式,將Fragment放進Activity已存在的ViewGroup裡。然而,Fragment並不是一定需要成為Activity Layout的一部份的,因為Android也允許Fragment在一個無自屬UI狀態下,當成Activity的"隱性工作人員(invisible worker)"。酷吧!

2.設計原理
Android在3.0(API level 11)的時候介紹了這個Fragments元件,主要是用來支援在large screen(平板)裡多種動態及彈性的UI互動。因為平板的螢幕通常比手持裝置還要大,因此,也得到了許多能夠合併或在畫面中做改變的空間。Fragment因為能夠到幫你處理複雜的view階層(View hierarchy)運算,包括將一個Activity的layout傳至fragments中,因此你能在程式執行時期(Runtime)夠修改Activity的樣貌,也能夠讓Activity去管理並保留每一個fragment被改變的狀態,如同前面所說,存在back stack(背景堆疊)中。

提了那麼多,我在這裡做點假設。想像一下,有一隻APP可以在畫面的左邊顯示文章列表,右側則是顯示文章的內容,這2個都是fragment組成,而且還同時存在一個Activity中,酷吧?
每一個fragment都擁有各自的生命週期回呼函式(lifecycle callback),而且也能處理他們各自輸入事件,因此,fragment跟一般的Activity(一頁拿來讀文章列表,另一個Activity拿來讀內容)是很不一樣的。看看底下的圖1就知道了。
圖1. 此範例說明了如何在一個平板的Activity中,使用2個UI模組,但又能在手持裝置中分開使用。

你應該將每個Fragment模組化,並且讓它們能在Activity中重複使用。因為每個Fragment都定義了自己的layout、操作行為和自己的生命週期回呼函式。然而,因為你可以在多個Activity中去使用單一個Fragment,你就必須去設計得讓它們是能被重複使用的,並且盡量避免設計從A fragment直接手動存取B fragment。這件事很重要,因為一個被模組化的fragment能夠允許你在不同的螢幕中去做不同的排列組合。
當你的APP是設計給平板和手持裝置使用時,你就能利用你能使用的螢幕空間,去做最好且客製化的畫面呈現優化。舉例來說,手持裝置也許需要將多個fragment分散成一個一個的UI畫面,並讓它們存在各自的Activity中。但是因為你用了fragment,當你在用平板尺寸開發時,你就能崁進2個Fragments,然而,手持裝置卻因為空間不足,因此無法讓2個Fragments並存。所以手持裝置的Activity A只能放文章列表,Activity B則是放文章內容。也因為用了Fragment,這隻APP就能在手持和平板上共存,並且相容得很好。

3.建立一個Fragment
要建立一個Fragment,你必須繼承Fragment(或者繼承Fragment的子類別)。Fragment類別的程式碼看起來跟Activity很像,它擁有和Activity雷同的call back(回呼函式),像是onCreate()、onStart()、onPause()和onStop()。事實上,如果你要將你已經開發的APP轉移植到fragment中,你只要將這些code從你Activity的callback函式轉放到各自的fragment回呼函式中就可以了。

在使用Fragment時,通常你會需要實作至少3個生命週期回呼函式,它們是︰

onCreate() - 這個回呼函式是系統在建立Fragment時會呼叫的函式,你應該在這個回呼函式中初始化一些必要的元件,好讓fragment之後在pause或stopped、resumed時能使用。
onCreateView() - 系統會在要畫fragment的使用介面的第1時間去呼叫這個回呼函式。如果你有自訂義的view,你必須在這個回呼函式中return 一個自訂義的view(而且必須回傳為root),當然,如果Fragment沒有自己的View,你就回傳null吧!
onPaue() - 當使用者要離開時,系統會呼叫它。當你要儲存什麼值時,就在這個時機去儲存吧!

大部份的APP應該實作至少上述3種回呼函式。但是其實每個Fragment都有更多的回呼函式是你應該要去處理的。等等還會提到。

三、其它

官方文檔已將Fragment翻譯成中本版,
前往閱讀。

Thursday, May 24, 2012

Google Play Subcription(auto renew)訂閱型服務上線!

Google Play訂閱型服務於美國時間2012/5/24發出了技術公報,
底下簡單列出幾項重點︰

  • 一定要先將APP上線(published)才能使用subscription服務
  • 一個APP內可含多種資費,售價一定要高於0.00
  • subcription的沙箱模式幾週後才會在開發者控制臺上線
  • 價格一旦訂了,就無法更改(更改的功能也要等幾週後開發者控制臺改版才提供)
  • 如果舊資費已上線,使用者也在使用了,後期如果調整資費,subcription仍會以舊資費向使用者扣款。
  • subcription的訂閱期間分2種-月租型年繳型
  • 透過Google Wallet跟使用者扣款
  • 每期的扣款都會寄一封e-mail通知使用者
  • Google會持續地跟同一張信用卡扣款
  • 關於退費,必須從Google Play-->[我的應用程式]裡去解約,不提供直接從APP做解約的動作
  • 當使用者按了退款,會算到週期結束才結束subcription服務(30或31天,視大小月而定)
  • 特殊狀況下,萬一使用者直接找廠商解約,還是可以透過自己的server並使用server-side API去跟Google做API方式的直接解約
  • subcription只支援有支援in-app-billing的國家
  • (台灣也算在內,請見官方in-app-billing支援國家列表)
  • Google Play app版本號必須在3.5以上,Android版號必須在2.2以上
  • 當使用者移除app時,Google會發出警告通知︰這隻APP仍在subcription服務下,並會詢問是否要解除該訂閱
  • subcription的退費模式遵照in-app-billing,需直接找廠商處理。
  • 即使退費了,服務仍會在使用者手機上維持1個月的cycle。
  • subcription一樣有30%的抽成

Friday, May 18, 2012

果合中介的廣告無法貼齊APP邊緣

就是這個xx
剛才發現果合的中介廣告,
陸出的廣告無法貼齊APP的邊緣,
多了5mm。

找很久才發現原因是因為果合後臺有提供一個close button,
那個button用了版面5pixel。

Saturday, May 12, 2012

NDK的相關知識

一、前言
JAVA在程式語言中,
算是高階語言(人類能理解的語言)。
由於JAVA的主要用途用在商業領域,
因此底層的架構是一層又一層的,
執行的效能可想而知就不如C(中階語言)的快速。

因此才有人會說︰
如果你寫的語言越接近組合語言(低階語言,也是電腦的語言),
執行起來當然就會是最快的。

Android因為提供了NDK,
因此可以將很多C語言的專案收納進來。
當然,
Google提供了NDK的支持,
主要也是因為其自由開放的特性,
更希望大量遊戲之類的專案,
能用進來Android領域被其推廣。

在遊戲畫面裡,
每個物件的處理都需要高度的演算,
這些演算如果使用JAVA來處理,
效能很差。
因此,
如果Android想要有遊戲的支持,
NDK的支持就變成了很重要的重點。

最有名用NDK的例子,
非Angry Bird莫屬。
Angry Bird在Android裡並非使用JAVA寫的,
而是C轉過來在Android上執行的。

二、文章開始
這裡先提及幾個可能需要了解的概念。

首先,
C語言會被放在Android Project的JNI目錄底下。

JNI目錄底下的.mk檔
告訴NDK建構系統(NDK build system)你的Native Code的相關資訊。

JNI目錄底下的.c檔
C語言檔。就好像JAVA檔的副檔名叫.java一樣

JNI目錄底下的.so檔
Android若要執行Native code,
並需先將C語言編譯且封裝成Library。
這個概念就好像我們在JAVA底下,
習慣將程式碼封裝成.jar給別的專案使用一樣。

要將Native code編譯成.so檔,
就要使用make.exe。

make.exe
這個檔案是GNU Make的檔,
功能是將Native code轉成library,
讓其它的程式可以使用。
make出來的檔案,
在Windows環境底下副檔名會是.dll,
而在Linux底下,副檔名就是.so了。

Wiki對於make的解釋
軟體開發中,make是一個工具程式(Utility software),經由讀取叫做「makefile」的文件,自動化建構軟體。它是一種轉化文件形式的工具,轉換的目標稱為「target」;與此同時,它也檢查文件的依賴關係,如果需要的話,它會調用一些外部軟體來完成任務。它的依賴關係檢查系統非常簡單,主要根據依賴文件的修改時間進行判斷。大多數情況下,它被用來編譯原始碼,生成結果代碼,然後把結果代碼連接起來生成可執行文件或者庫文件

在make前,
Android的Project需要有build.xml檔方可編譯,
要在命令提示字元底下、該專案目錄裡,打上指令︰
android update project -p . -s -t android-8
此時,
專案目錄底下就會產生build.xml檔,
這時候,再去對C語言做編譯。

Android也提供了一個快捷的方式make,
就是在專案目錄裡JNI目錄裡,下指令︰
ndk-build

Android一收到ndk-build指令,
便去找系統的make.exe,
幫你把這個C語言打包成Library,
並放進專案目錄底下的libs目錄裡,
副檔名為.so。

ndk-build這個檔案放在NDK目錄底下,
一打開目錄就可以看到了。
要在JNI目錄裡執行ndk-build,
你需要先設定好環境變數。

找不到make.exe
make是在安裝Cygwin的時候,
順便安裝下來的套件,
不要到剛才的GNU make網站去抓安裝包,
因為如果是用這種方式安裝,
屆時在Cygwin裡執行make時,
Cygwin會不認識你自己安裝的make指令哦!

安裝make也蠻簡單的
只要Cygwin在安裝套件包時,
輸入make關鍵字就可以找到了。




文章未完哩....

Thursday, May 3, 2012

百萬大學堂 開發日記

 一、前言
百萬大學堂在上線的2個星期內,
下載量正式破5萬人
也持續了1個星期台灣區APP下載前10名。

在這個部落格裡,
將這隻APP開發過程的三兩事記錄下來,
跟玩家們分享。

二、文章開始
[百萬大學堂]誕生

話說,
本來在餐飲業的我,
這樣子傻傻、不怕死的轉進資訊產業,
而且也因為愛死了那隻小綠人,
所以完全都沒有想的就踏入了Android領域。

這樣子奮鬥也快2年了,
我很想問我自己︰
我的程度到哪裡了?
我的作品能被市場認同嗎?
如果沒有公司要我了,我有自己活下去的能力嗎?

在參與了一次台北GTUG(台灣Android開發者討論社群)的聚會後,
得知三星即將舉辦一場App大賽,
廣邀全台灣Android開發者進來這場比賽,
凡事獲得晉級者,
皆可拿到免費的Samsung Note和Samsung Tablet。
這是一個證明我自己的絕佳機會。
後來,
百萬大學堂沒有得到三星App競賽初評的青睞。

我︰
「可惡,本來看上了SamsungAPP大賽只要APP有晉級,
便可以拿到免費的Note和Tablet,
但是卻沒入圍。
Note那臺規格那麼奇怪,
如果有一臺Note,
至少之後的開發,
還能稍微照顧一下Note的使用者。
現在算了啦,
我們也沒錢再買Note了。
海倫,我們轉向,
把這隻APP趕快做成可運行版本,
在Google Play上架吧!」


版本更新歷史
v1.0.0 - 大學堂上架

海倫是[百萬大學堂]的視覺美編,
我(小鰻)是程式設計 + 企劃發想。

我︰
「海倫,天啊,
真的會瘋掉,
你知道嗎?
我剛才拿我剛做好的程式,
去西門町三星通路實測,
在Note上完全跑版耶!
在平板上更慘!」

海倫︰
「驚!」

我︰
「一定要想一個辦法解決Android解析度不同的問題,
不然海倫妳圖會畫死,
我程式介面也會醜爆!」

v1.0.1 - 改進調成靜音後進不了程式的BUG
在v1.0.0版上架Google Play了以後…
我︰
「啊!我是豬頭嗎?
當我在設定裡,將音量調成靜音後,
遊戲進不去了!
凌晨3點,
快點修BUG!」

v1.0.2 - 能夠調整遊戲時間
海倫︰
「小鰻,網友在幹譙不能調時間啦!
一直在我們的評論裡面罵髒話!」

我︰「發生什麼事?」

海倫︰
「剛才我看了一下,上線到現在2天了,
目前差不多有500人下載了,
但是網友都狂幹譙耶…」

我︰
「500了哦?那有機會追過劉子千哦!(心裡暗爽中)」

我︰
「哦,好啦,那我趕快追加一個能調整遊戲時間的版本。」




v1.0.3 - 防小白篇
海倫︰
「小鰻,下載量破1000了,
但是網友現在都在罵我們,
說遊戲超爛的啦!
而且都給我們1顆星,
還跟我們說題目很少…!」

我︰
「這樣不行,
大學堂是我們的孩子,
我們做爸媽的,
有義務保護好孩子。
海倫,
你趕快上去,留一篇中肯一點的評論,
至少能稍微阻止玩家一直負評下去。
我也會添加"開學典禮",
藉由開學典禮告訴玩家可以設遊戲時間、我們有意見回報的功能。
才2個人是能想出多少題目,
你至少幫我上去止血一下。」

海倫︰
「嗯。」

v1.0.4 - 添加成績單回饋
我︰
「海倫喔~
我從第1版就跟你說,
玩家應該不會只想要看到成績,
畫面應該要有多一點的回饋才對,
上次跟你說的如果玩家得到100分,
小綠人會扭屁股,
如果得0分會3條線,
什麼時候才會畫給我啦!」

海倫︰
「哈哈,我選擇性忘記…」

我︰
「…」
「對了,記得喔,小綠人扭屁股的時候,
屁股要加上小叮噹的尾巴。」

海倫︰
「為什麼?那樣不會很奇怪嗎?」

我︰
「我也不知道,但做就對了。」

海倫︰
「哦…」

為什麼小綠人扭屁股會有小叮噹的尾巴
其實我到現在都還是不知道。
但是海倫畫的那個扭屁股,
我第1次看到動畫時,
連笑了5分鐘,
愛死你了,海倫~


v1.0.5 - 藍牙對戰版上線
海倫︰
「小鰻,嚇到我了啦,
網友開始激增,
而且還是負評不斷!」

我︰
「有什麼辦法,
看到他們一直說題目很少,
我現在就卡在藍牙連線對戰開發,
根本就沒時間找題目啊,
你知道藍牙層一直讓我原本的遊戲當掉
超麻煩的!
厚~
為什麼每次我都要挖洞給自己跳啦!
現在也只能趕趕趕,
快點把藍牙連線版釋出,
才有時間去找題目啦!」

海倫︰
「嗯…」

我︰
「在藍牙連線畫面,
海倫我希望用最簡單的流程,
讓玩家能夠完成藍牙連線的動作,
所以我會希望風格是簡單的,
玩家幾乎不用學習,
就能夠操作。」

海倫︰
「哦…(深思中...,其實是放空中。她自己說的)」

我︰
 「等等!海倫!
這2隻對抗的小綠人,
不應該只是對看,
他們中間應該要有火花!」

海倫︰
「厚~對看就有感覺了!幹嘛還要畫火花啦!」


我︰
不行!要有火花!

後來我把程式畫面實作出來後,
海倫她根本就超愛的,
她說電波有"死光"的感覺。

v1.0.8 - 張君亞傳奇(之所以打"張君亞",是因為"張君雅"侵權。)
我︰
「海倫,
當初我們一次把主題都擺上去書架上,
玩家好像都只玩前面一、兩個單元就不玩了,
這感覺不太對哦!
是不是有什麼方法可以鼓勵他們往後玩,
而不要都只玩前面1、2個單元就跟我們說遊戲很爛、沒深度啊?」

海倫︰
「(思考中)其實是再度放空中…」

我︰
「啊!
我想到了,
尋找張君雅
我們做一個單元,
內容是問玩家有關台灣的泡麵文化的相關問題,
主題取名為尋找張君雅。」

海倫︰
「好像還不錯唷!」

我︰
「可以把張君雅的名牌藏在其它主題的黑板或哪裡,
讓玩家去找它,
收集完後就可以開啟張君雅單元了。」

海倫︰
「不然我可以畫張君雅的笛子、書包…」

我︰
「嗯,先這樣吧…」

隔了一天,
早上6點,
睡夢中驚醒,
傳了WhatsApp給海倫︰
「海倫,
張君雅這件事情我們有一個地方不對,
我們要玩家收集的,
不應該是笛子、書包…,
應該要是筷子、湯匙和泡麵!
因為,
張君雅只吃泡麵!
這是上天賦予她的使命!」

海倫︰
「哦~。」

我︰
「筷子任務題藏進我是萬事通單元裡
問筷子的歷史。
湯匙則藏在另一個單元中,
玩家如果回答到任務題且答對,
就會獲得湯匙和筷子!」

玩家們,準備收集「筷子、湯匙和泡麵」吧!

希望這個創意,你們會喜歡哦!

 張君雅一夕爆肥!!!!
話說,
海倫畫給我的張君雅小妹,
本來是一個瘦子,
睡了一天醒來後︰
「海倫,那個張君亞有問題!
張君亞應該是個胖子!」

後來,海倫畫了胖子張君亞給我。
我︰
「哈哈哈,海倫你昨晚是讓張君雅吃了什麼,才一個晚上,胖那麼多!!」

三、總結
百萬大學堂,
仍在陸續改版中,
海倫也持續被我逼瘋中。

未完,待續。

四、後記
聯成電腦專訪百萬大學堂和我的求學經過


給我靈感

Sunday, April 29, 2012

不要怕犯錯

我親愛的朋友︰
如果你現在看到這篇文章,
那是因為我有感而發。

我覺得每個人都應該為自己的未來負責,
所以我跟朋友成立哈工作團隊,
我們利用閒暇之餘做「屬於自己」的APP。

經營了快1年,
每隻APP的廣告營收,
1天不到10塊錢台幣,
下載量更是微乎其微,
我犯的錯是︰我天真的以為我的創意和獨特化,消費者會懂
但是,他們跟創意發想的我們,
其實落差很大。

我做了決策工具,
這個工具很棒,
概念是從管理學的決策Matrix矩陣而來,
好幾次我在求職或做重大決策時,
因為有它,
所以在決定一件事時,
至少能有一點方向。

因此我把這隻APP實作出來,
第1版,反應還不錯,
但是也是累積了快半年,
才達到1,000下載人次。
這跟我當時做的「統一發票愛我」,
很快就達到1萬下載人次,根本無法比。

對於這個數據不死心的我,
又跟我的夥伴提議要做第2版更新。
這麼一改,
花了2個月,
界面也全換了,
並且跟我的夥伴說︰
我們一定會大賺。」
結果,
我跌得很痛。
放到現在快半年了,
還沒到500下載人次。

應該說,
除了挑戰劉子千這隻APP以外,
別摔小安(手機摔了會叫痛)、師父開示(每天看到一則好話)、寫春聯祝福朋友、
手機遺失保鑣…
沒有一隻跌得不慘。
所以到後來,
我已經沒有勇氣再跟我夥伴說︰「這隻一定大賺」了。

在寫程式,
往往是先有一個點子,
然後去做,
做完之後發現不對,
於是砍掉重練,
練了又不對,
又砍掉再練
一直這樣反反覆覆,
不知道過了N次才能成功。

在企劃一個案子也是,
一直想要獨特化,
然後遇到消費者不懂,
不死心又再次獨特化,
消費者仍然不懂,
最後只好調整自己的心態,
於是消費者懂了

即將上線的百萬大學堂「藍牙對戰版」,
關於藍牙的串接,
這隻APP應該被我開了又關不下1000次,
藍牙開開關關一天也至少100次…
整個程式的分層架構刪掉又建3次,
動畫模組修改了4次,
但這些東西,
都是消費者看不到的努力,
也是我一次次不斷犯錯、修改後的結果。

很開心,
百萬大學堂上線1週,
即破台灣區萬人下載,
現在在台灣總排行榜第16名。

我親愛的朋友,
不要怕犯錯。
因為你的成功,
都是因為你犯錯而獲得到的寶貴經驗。
千萬不要怕犯錯

小鰻 2012/4/30