2017年10月25日 星期三

Debug Android中的網頁

Debug Android中的網頁

在桌機上開發網頁時透過Chrome的開發人員工具可以很方便的進行除錯
當該網頁在特定手持裝置上跑時又該怎麼在該裝置下除錯呢?
我們可以使用 Chrome 的 inspect工具來達到這個需求。
該工具也可用在 Cordova 所開發的app中對 webview 進行Debug
前置條件:
  • Android 4.4 以上
  • Chrome 30 以上
1) 手機開啟 USB Debug功能:
    a) 啟用開發人員模式
        設定 --> 關於 --> 版本號碼  連點 7 次 該選項




        完成後在設定中會開發人員選項



    b) 啟用 USB 偵錯

2) 將手機接上USB後開啟桌機上的Chrome瀏灠器,
   在網址列上輸入: chrome://inspect
   可以在 Remote Target 上看到目前有連上的裝置


3) 開啟手機中的 Chrome 瀏灠器,開啟任網頁來測試
   ( 這邊以 www.pchome.com.tw 為例 )
    可以看到在桌機上的 chrome inspect 工具上出現我們在手機檢視的網頁項目


4) 點選 inspect 會開啟開發者工具來進行Debug
值得注意的是,左邊的畫面會和手機上的網頁同步,我們也可以直接在上面進行操作


如果使用Cordova開發App的話,也可以用相同方式來進行Debug




2017年10月24日 星期二

使用Ionic framework開發手機程式簡易範例

Ionic framework開發手機程式簡易範例

這是ionic framework在Windows 7作業系統下建置Android手機app的範例

1) 先安裝NodeJS
2) 開啟命令列視窗後輸入: npm install -g ionic cordova
3) 建立專案: ionic start MyFirstIonic



接下來會問你是要用什麼範本建立這個專案( ex. tabs, blank, sidemenu....),用鍵盤上下鍵來選擇範本,這邊就選tabs吧



專案建立好後會詢問是否把該專案加入Ionic的儀表板(dashboard),這些填 N 就好

4) 切換到專案目錄 cd MyFirstIonic
5) 我們可以用瀏灠器來測試專案: ionic serve



執行該指令後會自動開啟瀏灠器,若沒有自動開啟可自行於瀏灠器輸入http://localhost:8100
要結束server運行的話,該命令視窗以ctrl + C 便可結束



6) 要建置Android app須在電腦上安Android SDK或是安裝Android Studio
可參考Cordova Android Platform Guide
說明如下:

a) 安裝 Java JDK 8以上
b) 設定環境變數 JAVA_HOME


c) 安裝 Android Studio 來取Android SDK
d) 依所要建置的 Android 目標版本下載並新增SDK Package

開啟Android Studio --> Tools --> SDK Manager --> SDK Platforms 勾選要安裝的版本





e) 設定環境變數 ANDROID_HOME 並且將 android SDK路徑下的 tools/binplateform-tools 加至PATH




7) 執行 ionic cordova platform add android



8) 檢查ionic建置android 是否符合要求: ionic cordova requirements



9) 開始建置 ionic cordova build android
10) 建置完成後會產生android-debug.apk,這個 apk 就可以傳到手機上安裝了





11) 也可用adb(android debug bridge)的方法來建置佈署,手機以USB連接後先在命令列上下 adb devices 確認裝置是否已備妥

接著下 ionic cordova run android,直接建置後會安裝到手機上(記得先將手機設定為開發人員模式



相關連結

2017年10月20日 星期五

透過SSL For Free網站申請Letsencrypt SSL憑證

透過SSL For Free網站申請Letsencrypt SSL憑證

本範例為手動驗證的操作流程,申請者須對要申請的網站有存取檔案的權限

作業系統: Ubuntu 16.04.2 LTS
網站伺服器:  Apache/2.4.18

1.進入 https://www.sslforfree.com首頁,輸入要申請的網站DNS名稱 --> 點選 Create Free SSL Certificate


2.點選中間的Manual Verification,手動上傳驗證檔至欲申請的網站


3.上傳檔案 (目的是用來驗證申請者是真的有該網站的存取權限)
(1)先點選下載 Download File #1
(2)在網站根目錄中建立 .well-known 目錄,建好再到該目錄下建立 acme-challenge 目錄
(3)將步驟(1)所下載下來的檔案上傳至(2)所建的路徑 .well-know/acme-challenge/
(4)點選5點中所列的網址 例如 http://www.demo.com/well-known/acme-challenge/bXPtxVDs71Ca7MqC3jI7YPysHlFnP9UnBdpJ6W-E2IQ


若可成功存取的話會出現一串隨機產生的文字

下載 SSL 憑證檔案


將下載下來的三個檔案 ca_bundle.crt, certificate.crt, private.key 上傳到網站主機

編輯 000-default.conf ,設定憑證指向所上傳的憑證路徑:

vi /etc/apache2/sites-available/000-default.conf
<VirtualHost _default_:443>
SSLEngine on
SSLCertificateFile {憑證檔案存放路徑}/certificate.crt
SSLCertificateKeyFile {憑證檔案存放路徑}/private.key
SSLCertificateChainFile {憑證檔案存放路徑}/ca_bundle.crt
        ServerAdmin webmaster@localhost
        DocumentRoot {網站根目錄路徑}
</VirtualHost>


以Chrome開啟瀏灠已申請的網站 (例 https://xxx.xxx.xxx ),按F12 開啟開發人員視窗的Secuity頁籤中可檢視已申請的憑證

2017年10月19日 星期四

Java簡易電子發票資料Turnkey交換範例

Java簡易電子發票資料Turnkey交換範例

Turnkey應用教育訓練簡報檔中的Java範例只有片段,這邊以A0101進行實作。
import java.util.ArrayList;
import java.util.Calendar;
import com.tradevan.gateway.client.einv.parse.ParserException;
import com.tradevan.gateway.client.einv.parse.ParserHelper;
import com.tradevan.gateway.client.einv.transform.TransformException;
import com.tradevan.gateway.client.einv.transform.TransformHelper;
import com.tradevan.gateway.client.einv.validate.ValidateHelper;
import com.tradevan.gateway.client.einv.validate.proc.ValidateConstant;
import com.tradevan.gateway.client.einv.validate.proc.ValidateResult;
import com.tradevan.gateway.einv.msg.EINVPayload;
import com.tradevan.gateway.einv.msg.v31.A0101;
import com.tradevan.gateway.einv.msg.v31.A0101Body.AmountType;
import com.tradevan.gateway.einv.msg.v31.A0101Body.DetailsType;
import com.tradevan.gateway.einv.msg.v31.A0101Body.MainType;
import com.tradevan.gateway.einv.msg.v31.A0101Body.ProductItem;
import com.tradevan.gateway.einv.msg.v31.UtilBody.DonateMarkEnum;
import com.tradevan.gateway.einv.msg.v31.UtilBody.InvoiceTypeEnum;
import com.tradevan.gateway.einv.msg.v31.UtilBody.RoleDescriptionType;
import com.tradevan.gateway.einv.msg.v31.UtilBody.TaxTypeEnum;
public class GenMig {
public static A0101 genA0101Invoice() {
A0101 payLoad = new A0101();
MainType mainType = new MainType();
mainType.setInvoiceNumber("DX12345678");
mainType.setInvoiceDate(Calendar.getInstance().getTime());
mainType.setInvoiceTime(Calendar.getInstance().getTime());
RoleDescriptionType seller = new RoleDescriptionType();
seller.setIdentifier("100000001");
seller.setName("廁所蹲");
RoleDescriptionType buyer = new RoleDescriptionType();
buyer.setIdentifier("100000001");
buyer.setName("家裡蹲");
mainType.setSeller(seller);
mainType.setBuyer(buyer);
mainType.setInvoiceType(InvoiceTypeEnum.SixGeneralTaxType);
mainType.setDonateMark(DonateMarkEnum.NotDonated);
DetailsType detailsType = new DetailsType();
ArrayList<ProductItem> productItems = new ArrayList<ProductItem>();
ProductItem productItem = new ProductItem();
productItem.setDescription("測試品項1");
productItem.setQuantity("2");
productItem.setUnitPrice("100");
productItem.setAmount("200");
productItem.setSequenceNumber("1");
productItems.add(productItem);
AmountType amountType = new AmountType();
amountType.setSalesAmount(300L);
amountType.setTaxType(TaxTypeEnum.TaxFree);
amountType.setTaxRate("0");
amountType.setTaxAmount(0L);
amountType.setTotalAmount(300L);
payLoad.setMain(mainType);
payLoad.setDetails(detailsType);
payLoad.setAmount(amountType);
return payLoad;
}
public static void main(String[] args) throws Exception {
try {
EINVPayload payLoad = null;
payLoad = genA0101Invoice();
TransformHelper transformHelper = new TransformHelper();
EINVPayload latestPayLoad = transformHelper.transformToNewestVersion(payLoad);
ParserHelper helper = new ParserHelper();
String xml = helper.marshalToXML(latestPayLoad);
ValidateHelper validateHelper = new ValidateHelper();
ValidateResult validateResult = validateHelper.validateXML(xml, latestPayLoad.getClass());
if(ValidateConstant.SUCESS[0] != validateResult.getErrorCode()) {
throw validateResult.getException();
}else {
System.out.println("產生xml完成!");
System.out.println(xml);
}
} catch (TransformException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
view raw GenMig.java hosted with ❤ by GitHub

C# 簡易電子發票資料Turnkey交換範例

 C# 簡易電子發票資料Turnkey交換範例

        雖然財政部所提供的Turnkey軟體中 tv-gateway-einv-1.2.11.jar( 2020/12/25 更新:Tunkey 2.0.2版位於 cht-gateway-einv-2.0.0.0.jar )已經有建立各版本的資料交換完整的物件,考慮到java在目前公司尚未有人可以協助維護,所以想了一個比較簡易型套用樣版的方式來執行為了簡單快速,省去物件的建模,一切從簡有些XSD中的選填元素沒有一定得上拋就直接省略。

2020/12/25 補充: XSD 可以透過工具轉成 XML,可google關鍵字  XSD to XML

樣版工具使用:Mustache sharp 可至NuGet下載

程式碼參考如下:

主程式:Program.cs

其中利用 XmlReader 物件載入xsd來進行驗證xml產出是否符合規範

電子發票資料交換xsd檔可在tv-gateway-einv-1.2.11.jar中找到(參考附註)


樣版檔:templateA0401.txt

A0401物件:InvoiceA0401.csInvoiceA0401ProductItem.cs

完整程式可至GitHub下載


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ENVITest
{
class InvoiceA0401
{
/// <summary>
/// 發票號碼
/// </summary>
public string InvoiceNumber;
/// <summary>
/// 發票產生日期
/// </summary>
public string InvoiceDate;
/// <summary>
/// 發票產生時間
/// </summary>
public string InvoiceTime;
/// <summary>
/// 賣方-營業人統一編號
/// </summary>
public string SellerIdentifier;
/// <summary>
/// 賣方-營業人名稱
/// </summary>
public string SellerName;
/// <summary>
/// 買方-營業人統一編號
/// </summary>
public string BuyerIdentifier;
/// <summary>
/// 買方-營業人名稱
/// </summary>
public string BuyerName;
/// <summary>
/// 發票類別 詳細定義請參考InvoiceTypeEnum 資料元規格
/// 01:三聯式
/// 02:二聯式
/// 03:二聯式收銀機
/// 04:特種稅額
/// 05:電子計算機
/// 06:三聯式收銀機
/// 07:一般稅額計算之電子發票
/// 08:特種稅額計算之電子發票
/// </summary>
///
public string InvoiceType;
/// <summary>
/// 彙開註記(選項) 彙開需要填入"*"
/// </summary>
public string GroupMark;
/// <summary>
/// 捐贈註記 詳細定義請參考DonateMarkEnum 資料元規格
/// </summary>
public string DonateMark;
/// <summary>
/// 發票金額
/// </summary>
public string SalesAmount;
/// <summary>
/// 稅 類別
/// </summary>
public string TaxType;
/// <summary>
/// 稅制
/// </summary>
public string TaxRate;
/// <summary>
/// 稅額
/// </summary>
public string TaxAmount;
/// <summary>
/// 發票含稅
/// </summary>
public string TotalAmount;
/// <summary>
/// 折讓金額
/// </summary>
public string DiscountAmount;
/// <summary>
/// 外幣原幣金額 (選項)
/// </summary>
public string OriginalCurrencyAmount;
/// <summary>
/// 匯率 (選項)
/// </summary>
public string ExchangeRate;
public List<InvoiceA0401ProductItem> ProductItems;
}
}
view raw InvoiceA0401.cs hosted with ❤ by GitHub
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ENVITest
{
class InvoiceA0401ProductItem
{
/// <summary>
/// 產品名稱
/// </summary>
public string Description;
/// <summary>
/// 數量
/// </summary>
public string Quantity;
/// <summary>
/// 單位
/// </summary>
public string Unit;
/// <summary>
/// 單價(本幣)
/// </summary>
public string UnitPrice;
/// <summary>
/// 小計金額
/// </summary>
public string Amount;
/// <summary>
/// 序號
/// </summary>
public string SequenceNumber;
}
}
using Mustache;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace ENVITest
{
class Program
{
static void Main(string[] args)
{
string templatePath = @"templateA0401.txt";
String templateA0401 = File.ReadAllText(templatePath);
HtmlFormatCompiler compiler = new HtmlFormatCompiler();
Generator generator = compiler.Compile(templateA0401);
InvoiceA0401 InvoiceA0401 = new InvoiceA0401();
InvoiceA0401.InvoiceNumber = "QE00000000";
InvoiceA0401.InvoiceDate = "20171019";
InvoiceA0401.InvoiceTime = "16:20:17";
InvoiceA0401.SellerIdentifier = "1234567890";
InvoiceA0401.SellerName = "家裡蹲";
InvoiceA0401.BuyerIdentifier = "0123456789";
InvoiceA0401.BuyerName = "廁所蹲";
InvoiceA0401.GroupMark = "*";
InvoiceA0401.DonateMark = "0";
InvoiceA0401.InvoiceType = "07";
InvoiceA0401.SalesAmount = "0";
InvoiceA0401.TaxType = "1";
InvoiceA0401.TaxRate = "0.05";
InvoiceA0401.TaxAmount = "5";
InvoiceA0401.DiscountAmount = "0";
InvoiceA0401.TotalAmount = "105";
InvoiceA0401.DiscountAmount = "0";
InvoiceA0401.ProductItems = new List<InvoiceA0401ProductItem>();
InvoiceA0401ProductItem productItem = new InvoiceA0401ProductItem();
productItem.Description = "測試品項";
productItem.Quantity = "1";
productItem.Unit = "個";
productItem.UnitPrice = "100";
productItem.Amount = "100";
productItem.SequenceNumber = "1";
InvoiceA0401.ProductItems.Add(productItem);
string resultXML = generator.Render(new
{
InvoiceA0401 = InvoiceA0401
});
//驗證產出的XML是否符合xsd的規範
XmlReaderSettings xmlReadersettings = new XmlReaderSettings();
xmlReadersettings.Schemas.Add("urn:GEINV:eInvoiceMessage:A0401:3.1",@"EInvoiceXSD/v31/A0401.xsd");
xmlReadersettings.ValidationType = ValidationType.Schema;
XmlReader reader = XmlReader.Create(new StringReader(resultXML), xmlReadersettings);
XmlDocument document = new XmlDocument();
try
{
document.Load(reader);
Console.Out.WriteLine(String.Format("XML產出完成"));
System.Diagnostics.Debug.WriteLine("XML產出完成");
System.Diagnostics.Debug.WriteLine(resultXML);
}
catch (XmlSchemaValidationException ex)
{
Console.Out.WriteLine(String.Format("<p>XML驗證錯誤: {0}</p>", ex.Message));
System.Diagnostics.Debug.WriteLine(String.Format("<p>XML驗證錯誤: {0}</p>", ex.Message));
}
}
}
}
view raw Program.cs hosted with ❤ by GitHub
<?xml version="1.0" encoding="utf-8"?>
<Invoice xsi:schemaLocation="urn:GEINV:eInvoiceMessage:A0401:3.1 A0401.xsd" xmlns="urn:GEINV:eInvoiceMessage:A0401:3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Main>
<InvoiceNumber>{{InvoiceA0401.InvoiceNumber}}</InvoiceNumber>
<InvoiceDate>{{InvoiceA0401.InvoiceDate}}</InvoiceDate>
<InvoiceTime>{{InvoiceA0401.InvoiceTime}}</InvoiceTime>
<Seller>
<Identifier>{{InvoiceA0401.SellerIdentifier}}</Identifier>
<Name>{{InvoiceA0401.SellerName}}</Name>
</Seller>
<Buyer>
<Identifier>{{InvoiceA0401.BuyerIdentifier}}</Identifier>
<Name>{{InvoiceA0401.BuyerName}}</Name>
</Buyer>
<InvoiceType>{{InvoiceA0401.InvoiceType}}</InvoiceType>
{{#if InvoiceA0401.GroupMark}}
<GroupMark>*</GroupMark>
{{/if}}
<DonateMark>{{InvoiceA0401.DonateMark}}</DonateMark>
</Main>
<Details>
{{#each InvoiceA0401.ProductItems}}
<ProductItem>
<Description>{{Description}}</Description>
<Quantity>{{Quantity}}</Quantity>
<Unit>{{Unit}}</Unit>
<UnitPrice>{{UnitPrice}}</UnitPrice>
<Amount>{{Amount}}</Amount>
<SequenceNumber>{{SequenceNumber}}</SequenceNumber>
</ProductItem>
{{/each}}
</Details>
<Amount>
<SalesAmount>{{InvoiceA0401.SalesAmount}}</SalesAmount>
<TaxType>{{InvoiceA0401.TaxType}}</TaxType>
<TaxRate>{{InvoiceA0401.TaxRate}}</TaxRate>
<TaxAmount>{{InvoiceA0401.TaxAmount}}</TaxAmount>
<TotalAmount>{{InvoiceA0401.TotalAmount}}</TotalAmount>
<DiscountAmount>{{InvoiceA0401.DiscountAmount}}</DiscountAmount>
{{#if InvoiceA0401.OriginalCurrencyAmount}}
<OriginalCurrencyAmount>{{InvoiceA0401.OriginalCurrencyAmount}}</OriginalCurrencyAmount>
{{/if}}
{{#if InvoiceA0401.ExchangeRate}}
<ExchangeRate>{{InvoiceA0401.exchangeRate}}</ExchangeRate>
{{/if}}
</Amount>
</Invoice>

附註:安裝完Turnkey程式後可在 C:\Program Files\EINVTurnkey\lib 下找到 tv-gateway-einv-1.2.11.jar ( 2020/12/25 更新:Tunkey 2.0.2版位於 cht-gateway-einv-2.0.0.0.jar )

透過解壓縮工具解開後的xsd資料夾中可發現各版本的xsd都位於此

Windows 7 列出所有加密檔案

Windows 7 列出所有加密檔案


電腦開機時出現對話視窗: 詢問是否備份您的檔案加密憑證與金鑰


為什麼要備份加密憑證及金鑰呢? 因為如果檔案是有設為加密的,那麼該檔案就只有加密的使用者才可開啟 非該使用者要開啟時都會發生存取被拒。 假如電腦重灌後或是檔案移至其他地方,要開啟時若沒有備份加密憑證及金鑰這時就無法讀取啦~

因沒印象有對任何檔案做過任何的加密,要知道電腦有哪些檔案有做過加密可透過cipher指令查詢:
cipher /U /N /H

參數說明:
/U :嚐試抓取在本機電腦中所有加密檔案,若檔案有異動過會去更新或修復加密金鑰
/N :用來和 /U 搭配,表示只查找不做加密金鑰的更新
/H :一併顯示隱藏檔和系統檔


以下指令會將結果輸出至 Encrypted-Files.txt
cipher /U /N /H > Encrypted-Files.txt

延伸問題:如果我們要在Windows 對資料做加密該怎麼做呢?
在資料夾或檔案上按滑鼠右鍵--> 內容
一般 --> 進階

勾選「加密內容,保護資料」 --> 確定


可以看到該目錄或檔案呈現綠色


相關連結

2017年10月18日 星期三

Notepad++ 將字串取代為換行符號方式

Notepad++ 將字串取代為換行符號方式

將特定字串取代為換行符號


將換行符號取代為特定字串

IE11 相容性檢視重開機後不見


IE11 相容性檢視重開機後不見

問題描述:IE11 設定相容性檢視設定後一重開機又消失不見了


解決方式:網際網路選項 --> 一般 --> 取消勾選「結束時刪除瀏覽歷程紀錄」


參考資料: Issues With Internet Explorer 11 Not Saving

2017年10月16日 星期一

Thumbs.db無法刪除問題解決方式

Thumbs.db無法刪除問題解決方式

Windows在具有圖片資料夾下,會自動產生「Thumbs.db快取縮圖」, 而這個檔案就是保存這些預覽小圖的檔案,常見問題是要刪除資料夾時會出現"Windows 檔案總管 已開啟此檔案,所以無法完成動作"

解決方式:
調整檢視為"圖示"的呈現方式之後就可以進行刪除了

2017年10月12日 星期四

CSS Display 屬性範例


display 的屬性值有 block, inline, none

block:以新的一列方式呈現,寬度會儘可能延伸至最左及最右 例如 Div 這個元素就是 block 類別
inline:不以新的一列方式呈現,寬度只佔所需的大小 例如 span 這個元素就是 inline 類別
display設為 none 時該元素將為不可見
example:
原 a 元素預設值為 inline
第一個連結 第二個連結 第三個連結
將 a 元素改為 block方式呈現:
第一個連結 第二個連結 第三個連結
程式碼:
<p>原 a 元素預設值為 inline</p>
<a href="#" target="_blank">第一個連結</a>
<a href="#" target="_blank">第二個連結</a>
<a href="#" target="_blank">第三個連結</a>
<p>將 a 元素改為 block方式呈現:</p>
<a href="#" class="display-block" target="_blank">第一個連結</a>
<a href="#" class="display-block" target="_blank">第二個連結</a>
<a href="#" class="display-block" target="_blank">第三個連結</a>
view raw index.html hosted with ❤ by GitHub
<style>
.display-inline {
display: inline;
}
.display-block{
display: block;
}
</style>
view raw style.css hosted with ❤ by GitHub

CSS 置中方式


CSS 置中方式


我被置中了
margin : auto;會使容器置中 max-width : 200px;寬度最大不超過200px, 父容器縮小到200px以下時不會出現scrollbar.而是自動縮減寬度
程式碼如下:
<p class="custom-center">我被置中了</p>
view raw index.html hosted with ❤ by GitHub
.custom-center{
max-width:500px;
margin: auto;
border: 3px solid #73AD21;
}
view raw style.css hosted with ❤ by GitHub