2019年8月1日 星期四

【Google】如何將SheetSpread表格內的資料轉換成JSON

其實Google自己有自己的工具,但轉換出來的資料複雜的不合理。




所以找了一下,發現有神人製作了一個工具「http://gsx2json.com/」...

可以將第一列視為「Tag」,然後將每一欄作為一筆資料,用該欄第一列的資料作為Tag進行資料分類索引。




利用工具後...「http://gsx2json.com/api?id=1bRM_dIcl67MgLinJfc_YBqifZ65vusun5XJLWHQZ_oM&sheet=1&columns=false

轉換出的資料變成「{"rows":[{"標題":"測試一","內容":"測試內容1","參數":100},{"標題":"測試二","內容":"測試內容2","參數":1002},{"標題":"測試三","內容":"測試內容3","參數":1002}]}」

這樣的規格明顯合理許多。

也有別的參數可以調整...「http://gsx2json.com/api?id=1bRM_dIcl67MgLinJfc_YBqifZ65vusun5XJLWHQZ_oM&sheet=1

{"columns":{"標題":["測試一","測試二","測試三"],"內容":["測試內容1","測試內容2","測試內容3"],"參數":[100,1002,1002]},"rows":[{"標題":"測試一","內容":"測試內容1","參數":100},{"標題":"測試二","內容":"測試內容2","參數":1002},{"標題":"測試三","內容":"測試內容3","參數":1002}]}」

2019年7月12日 星期五

【Android Html5】播放Youtube影片

目標是建立一個會佔滿整個WebView的YouTubePlayer。

必須注意到:基本上,開發時所有會遇到的問題都源於「網頁版Youtube撥放器在移動網頁上不能正常運作」。──所以Google才會另外開發一套移動式套件,但因為這套件非常不好用,所以終究還是要回來解決不能正常運作的問題。


基本建立方式在第二個回應。(測試過,可以使用。)

這個技巧播放檔案的秘訣在於監聽Player的State,所以當它Ready就開始播放,播放完可以開始再次重播、或撥下一檔。

如果要改撥放PlayList、而不是單一影片,可以使用這個方法修改範例。

範例內是使用在YT.Player內直接設定VideoId的方式,但其實有用播放指令指定ID的方法,同時也可以用清單播放。方法可以看標準官方範例。

官方範例內有player.nextVideo(),可以用來自動播放列表下一檔。


影片如果要不暫停、就退出或前進到下一層功能,這個地方有講解需要使用什麼樣的修改。簡而言之就是WebView也有自己的onPause和onResume,必須要在Fragment和Activity中相對應的地方呼叫。(同時需要使用Timer的啟動與暫停。)

另外,影片如果還沒開始撥放就被退到背景,YouTube Player這時可能會在背景被啟動。所以在執行「是否要開始撥放」前,同時要檢查WebView是否還在前景上。



2019年4月10日 星期三

【Android AES】SHA1PRING + Crypto

Google提供的範例檔案


好像是Android6以後,AES加解密如果是使用SecureRandom這個物件搭配演算法「SHA1PRING」和Provider「Crypto」來取得RawKey(用來產生SecretKeySpec時需要的導入參數),會發生失敗的情況。

雖然Google提供了一組叫做CryptoProvider的物件在網路上讓人下載(或複製貼上),但在Cipher進行解密(執行dofinal這個函數)時一樣會出錯。

Google這個超級天才就繼續提供了一組物件叫做「InsecureSHA1PRNGKeyDerivator」在網路上,(載點在上面,)來解決這個問題。


這個物件的用法很單純,就是呼叫一組static物件取得Instance然後再導出 RawKey即可。

方法大概是這樣...

byte[] raw = InsecureSHA1PRNGKeyDerivator.deriveInsecureKey(seed, 16);

比較詭異、比較巧妙的是這個「16」,因為大多數使用這個物件的範例都使用「32」,可是解密部分一樣會在Cipher的地方出錯。這似乎是看你使用的Key長短而定,或是你設定的加密位元。

(32是256位元?16是128位元?)

其他部分都可以循著一般標準範例。

2019年2月19日 星期二

【Android】Mac Adress的可用求法(純Java、不含Android API)

根據官方文件的說法,所有可行的Android API都已經不可以取得Mac Address。

所以要取得Mac Address,必須要回歸原始Java方法。


public static String getMacAddr() {
    try {
        List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
        for (NetworkInterface nif : all) {
            if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

            byte[] macBytes = nif.getHardwareAddress();
            if (macBytes == null) {
                return "";
            }

            StringBuilder res1 = new StringBuilder();
            for (byte b : macBytes) {
                String hex = Integer.toHexString(b & 0xFF);
                if (hex.length() == 1)
                    hex = "0".concat(hex);
                res1.append(hex.concat(":"));
            }

            if (res1.length() > 0) {
                res1.deleteCharAt(res1.length() - 1);
            }
            return res1.toString();
        }
    } catch (Exception ex) {
    }
    return "";

簡單來說就是去取得無法閱讀的編碼然後轉換成Mac Address格式。(但也不是真的無法閱讀,只是送出的資料為數值,要轉16進位、還要轉成統一文字格式。

方法很簡單,但是困死許多人。



2019年2月18日 星期一

【Android】APP內部的「返回APP首頁」

(思考這個題目的目的在於........官方所提供關於Activity的某些控制機制其實邏輯不明確,很難知道照表操課的結果,所以會想要思考如何自己「實作一套機制」。)

雖然已經有Fragment,可以讓開發者用「切換」Fragment來製造「回到首頁」的效果,但這種做法其實極限很多。

問題在於「產品設計」通常不會希望APP設計上的「使用流程」受到嚴格拘束,他們總是會希望「APP的功能可以自由地切換。」


嚴格拘束、嚴格規範過的APP操作流程基本上都是樹狀圖。

假設首頁是Activity,下面的幾個主功能則是Activity1、Activity2、Activity3...

如果Activity1下面還有子功能,則是Activity1_1、Activity1_2、Activity1_3...

在Activity1內新增一個static的布林值,假設命名為「Close」,則Activity1_1、Activity1_2、Activity1_3內(還有未來可能延伸出來「子功能的子功能」)的「首頁」鍵按下後都會把這個Close的內容改為true。

另外在Activity1的onResume內檢查它的值,如果為true就把這個Activity關閉,如果false就繼續執行正常功能。

但記得永遠在onCreate內將Close設為false。因為如果經過onCreate就表示這個Activity是被正常且完整的流程給啟動的,可以視為一個「新的呼叫或使用」。

以此類推,Activiy1_1內也可以有自己的Close,讓 Acitivity1_1_1、Activity1_1_2....可以關閉。


這樣的缺點是「APP的操作路徑必須永遠是樹狀的。不同的樹枝之間不可以隨意橫跨呼叫。」


有辦法克服嗎?.......當然有,但是那必須要用靈魂交換.......開玩笑的。

其實這個方法反而相較簡單,但要使用它,必須要對Activity的生命週期應用非常嚴謹。




但最理想的方式是使用「ActivityLifecycleCallbacks」。

(注意!這個方法跟上述的方法是互相矛盾不可並行的。)

一般來說返回首頁會是個按鈕,則可以將這個按鈕統一用一個View類別來擴稱,不管是哪個類別,假設擴充之後的名稱為「HomeCall」。

HomeCall基本上是個要用在XML Layout檔中的類別,並不需要在個別Activity中使用它,(但要使用也可以,必須斟酌發揮一些巧思,)在建構子中使用傳入的Context去將「ActivityLifecycleCallbacks」實作並呼叫。

(應該已經有人知道我要做什麼了。)

然後一樣設置一個static的布林參數,假設命名為「HomeCall」.......(這地方可以依照實務上的需要做調整,不用布林改用其他數值參數也可以。)

在這個View自身上設置OnClickListener,然後內容設計為「一律將HomeCall設為false」,然後在之前實作的「ActivityLifecycleCallbacks」中的「onActivityResume」設計為「一律將傳入的Activity關閉」.......



【未完】

2019年2月11日 星期一

【Android】修改螢幕亮度

應該是Android 6.0以後,這類的硬體功能調整光是在Manifest檔中加上「User-Permission」並不夠,還需要有「權限啟動」的通知。

Intent intent1 = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);intent1.setData(Uri.parse("package:" + getPackageName()));intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent1);

方法大概如上。這個功能會啟動特定APP的權限管理頁,讓使用者決定是否要自己打開權限。

但在執行這行之前,要詢問系統是否有「執行他們」的能力,--是否有修改Setting的權限。

Settings.System.canWrite

這是個函數,後面要傳入「Activity」作為參數。

如果回傳false,就表示權限未開啟,如果執行程式碼會導致當機。


之後就是很一般的程式碼,直接取得Setting類別後,要求修改特定參數。

android.provider.Settings.System.putInt(
        getContentResolver(),        android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE,        android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);android.provider.Settings.System.putInt(
        getContentResolver(),        android.provider.Settings.System.SCREEN_BRIGHTNESS,        brightNeess);

brightNeess這個參數要自己自訂。(寫死?或是可以讓使用怎選取、輸入想要的數直。)