2016年5月9日 星期一

C#的dll檔如何讓Foxpro 呼叫


    相信許多人維護舊有的系統,不得不牽就目前的系統環境,例如foxpro 已經維運了半世記了,無法相容於c#的技術,但c#保留其彈性,讓它可以被宣告成dll檔直接被foxpro直接呼叫,讓舊有的系統也能使用c#的功能,這是多酷的事情。

步驟一: 設定Visual Studio Tool 的環境

勾選 【讓組件成為COM-Visible(M)

勾選註冊COM Interop

步驟二: c# 的範例程式碼
namespace sample
{
    [ClassInterface(ClassInterfaceType.AutoDual)] //雖然不明白這行,但查詢文件都要加上此行
    [ProgId("sample.bt")]  //sample (專案的名稱) . bt(類別名稱
    public class bt
    {
        public string search_bt()
        {
            return "this is XXXXX search_bt";
        }
        public string search_bt2(string fl)
        {
            return fl;
        }
        public string search_bt3()
        {
            return "the new function";
        }
    }
}

步驟三:foxpro的範例程式

步驟四: 註冊c#dll元件

到指定Framework的目錄下,用regasm 路徑/檔名.dll


執行結果:

2016年3月1日 星期二

Android 首部曲-Customer ListView

Android 的開發者果然是佔大多數,至今java語言仍是排前三大,雖然PhoneGap 是一個不錯的開發工具,但是你想設計更複雜的介面,還是只能寫原生的Android APP的語言『JAVA,以下就介紹最常見的範例ListView

一、瞭解Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.test.MainActivity" >

    <ListView
        android:layout_width="match_parent"  
        android:layout_height="match_parent"
        android:id="@+id/list_view"       />
    <Button      
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:text="@string/self_destruct"
     android:onClick="selfDestruct"
     android:layout_alignParentBottom="true"
     android:layout_alignParentRight="true"   
       />   
</RelativeLayout>

每份Android文件中都有一份layout.xml是主畫面的設計畫面,你可以在這文件中加上任何的控件等等,也包括listview button 等等,以下常見的參數
 android:layout_width : 控件的寬度,
match_parent:佔滿整個版面
fill_parent: 佔滿整個版面
wrap_content:依你的內容物大小決定,例如文字型的按鈕,會依照文字行列決定控件的大小
android:layout_height: 控件的高度,參數同上
android:id="@+id/list_view"  : 控件的id名稱 ,它的id名稱為list_view  

二、建立客製化的ListView

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:orientation="horizontal" >
     <ImageView
           android:id="@+id/icon"
           android:layout_width="50dp"
           android:layout_height="50dp"
           android:layout_marginBottom="5dp"
           android:layout_marginLeft="5dp"
           android:layout_marginRight="5dp"
           android:layout_marginTop="5dp"
           android:src="@drawable/ic_launcher" />
     <TextView
           android:id="@+id/Itemname"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:textSize="20sp"
           android:paddingTop="5dp"/>
</LinearLayout>

為何已經有主版面的Layout為何就需要另外新增Layout?  因為想要客製化自己style 風格的ListView所以就需要另外新增,內容和主版面很像,這樣版中使用LinearLayout 就代表會像線性一樣放置控制,參數如下說明

android:orientation="horizontal" :  以水平的方式,放置控件,由左到右的方向
android:id="@+id/Itemname"  :這是設定id的名稱 @+id JAVA 就可以透過 r.id.Itemname 取得該物件,Itemname是你自訂的名稱,你可以改任何的名稱

以上的範本中,依序順序擺放位置,圖片會在文字的左邊,其他參數應該猜得到意思吧其中圖片的屬性android:src="@drawable/ic_launcher"  作者百思不得其解,原來Android目錄中res有五個都是以開頭為drawable命名的目錄,是擺放不同解析度的圖片喔,所以ic_launcher 就是圖片名稱啦~

三、建立客製化的ListView的類別
Pen.java :  //用來傳遞變數的物件
public class pen {
     public String  name
     public pen(String name)
    {
        this. name = name;      
    }
}

myAdapter.java
package com.example.test;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class myAdapter extends ArrayAdapter<pen> {
// 建立arrayList<object> 將資料帶進來,用來產生listivew 的資料
      public myAdapter(Context context, ArrayList<pen> pens) {
            super(context, 0, pens);
         }
      @Override
         public View getView(int position, View convertView, ViewGroup parent) {
            pen penObj = getItem(position);       // 取得pen 物件,
            if (convertView == null) {
//透過r.layout.listview 語法,取得在res/layout/listview.xml
               convertView = LayoutInflater.from(getContext()).inflate(R.layout.listview, parent, false);
            }
//透過r.id.ItemName 語法,取得在res/layout/listview.xml  id為【ItemName】的控件
            TextView itemName = (TextView) convertView.findViewById(R.id.Itemname);         
            itemName.setText(penObj.name); //填入文字      
            return convertView;
        }
}

為何有R 這個物件,原來是Android提供方便工具,我們在res在之前的listviewLayout中已經設定@id的名稱,所以透過r.id.XXX就可以取得該物件,當然也可以透過r.layout.名稱取得res/layout/ layout範本,這點是不熟Android開發方法的朋友們,需要注意的喔!!!

四、在主頁面的Activity 呼叫客製化的ListView

public class MainActivity extends Activity {
    private ListView listView;   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ArrayList<pen> pens = new ArrayList<pen>();
        pens.add(new pen("鉛筆"));
        pens.add(new pen("原子筆"));
        pens.add(new pen("鋼筆"));
        pens.add(new pen("毛筆"));
        pens.add(new pen("鉛筆"));
       //建立pen 的物件集合,傳遞給自訂的listview
        myAdapter customerAdapter = new myAdapter(this,pens);       
//在主畫面的layout 取得listiview 控件
        listView=(ListView)findViewById(R.id.list_view);
//換成自訂的listiview範本
        listView.setAdapter(customerAdapter);     
    }
}

總結以上第一次的Android開發心得…   雖然不難但是有許多的參數要去查詢,Androiddeveloper 的文件非常的詳細,只要多多善加利用,你我也都是Android的開發者






2016年2月3日 星期三

Cordova推播 parII-c#如何推播IOS裝置

一、下戴IOS的憑證
憑證輔助程式à 為憑證授權要求憑證à儲存至桌面
 

選擇App IDs




 
登入App IDS,勾選Push Notifications














將私鑰匯出後,上傳到Push Notifications,並下戴相關憑證



開啟keyChainè 鑰匙圈點選【登入】, 類別點選【憑證】



在IOS Push Services 的專用密鑰-->按下右鍵匯出匯出成.p12


切記:要有兩份p.12  因為一份是開發人員,另一份是正式環境下使用憑證


二、部署到客戶的端的APP程式

引用相關的函式庫
<script type="text/javascript" src="//cdn.pubnub.com/pubnub-3.7.4.min.js"></script>
<script src="cordova.js"></script>
<script src="scripts/platformOverrides.js"></script>    

config.xml 加入推播的外掛程式
https://github.com/phonegap-build/PushPlugin.git

目前測試最新版的2.5.0 會出現問題,但安裝2.4.0卻很正常,原因不明,請各位自行測試

如果在mac環境下建立的cordova 需要下指令外掛
cordova plugin add https://github.com/phonegap-build/PushPlugin.git



接收推播訊息和手機裝置碼
var pushNotification;
(function () {
    "use strict";
    document.addEventListener('deviceready', onDeviceReady.bind(this), false);
   function onDeviceReady() {      
        pushNotification = window.plugins.pushNotification;    
        //IOS裝置 :註冊ID
        pushNotification.register(tokenHandler, errorHandler, { "badge": "true", "sound": "true", "alert": "true", "ecb": "onNotificationAPN" });
        document.addEventListener('pause', onPause.bind(this), false);
        document.addEventListener('resume', onResume.bind(this), false);      
    };  
    function successHandler(result) {
        alert("success OK");
    }
    function errorHandler(error) {
        alert('失敗');
    }
    function tokenHandler(result) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", "http://192.168.1.63/codovaWebAPI/api/apiPatient/registID/" + result + "/platform/IOS", true); // 儲存手機的註冊ID,這要自己寫  WEB API
        xmlhttp.send();
        navigator.notification.alert(result, null, 'Alert', 'OK');
        sessionStorage.setItem("deviceId", result);
        sessionStorage.setItem("notificationServer", "APNS");
    }
    function onNotificationAPN(e) {
        if (e.alert) {
            navigator.notification.alert(e.alert);
        }
        if (e.sound) {
            var snd = new Media(e.sound);
            snd.play();
        }
// 它可以在ICON圖示上面顯示號碼喔
        if (e.badge) {
            pushNotification.setApplicationIconBadgeNumber(successHandler, e.badge);
        }
    }


三、asp.net MVC建立推播的網頁

view 的樣版
<div>
    <form method="post">
       <label>請輸入推播的裝置ID</label>
       <input type="text" name="deviceID" />
       <label>請輸入推播內容</label>               
       <input type="text" name="pushMessage" />
      <input type="submit" />
    </form>
</div>

Controler
  [HttpPost]
        public ActionResult Index(string deviceID, string pushMessage)
        {
//有多種裝置平台 (所以作者將其包裝物件,到時就取用哪種裝置的推播方式)
              Notification.pushMessage pushMessageObj = new Notification.pushMessage();
              pushMessageObj.SendIPhoneNotification(deviceID, pushMessage); //呼叫Ipone的推播模式
              return View();
        }

PushMessage.cs


ios特有的傳輸格式,要符合以下格式



   public bool SendIPhoneNotification(string deviceID, string message)
        {
            int port = 2195;  
            String hostname = "gateway.sandbox.push.apple.com"
//記得mac匯出推播的私有憑證 .p12 要放在專案中才可以推 播成功,因為要需要APN驗證
            String certificatePath = HttpContext.Current.Server.MapPath("~/Certificate/ckDeveloper.p12"); //上式上線部署app後,要改為正式版
            X509Certificate2 clientCertificate = new X509Certificate2(System.IO.File.ReadAllBytes(certificatePath), "16145679");//匯出憑證使用的密碼
            X509Certificate2Collection certificatesCollection = new X509Certificate2Collection(clientCertificate);
            TcpClient client = new TcpClient(hostname, port);
            SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
            try
            {
                sslStream.AuthenticateAsClient(hostname, certificatesCollection, System.Security.Authentication.SslProtocols.Tls, true);
                MemoryStream memoryStream = new MemoryStream();
                BinaryWriter writer = new BinaryWriter(memoryStream);
                writer.Write((byte)0);
                writer.Write((byte)0);
                writer.Write((byte)32);
                writer.Write(HexStringToByteArray(deviceID.ToUpper()));
//設定推播的訊息,badge: icon 上顯示通知數
                String payload = "{\"aps\":{\"alert\":\"" + message + "\",\"badge\":1,\"sound\":\"default\"}}";
                writer.Write((byte)0);
                writer.Write((byte)payload.Length);
                byte[] b1 = System.Text.Encoding.UTF8.GetBytes(payload);
                writer.Write(b1);
                writer.Flush();
                byte[] array = memoryStream.ToArray();
                sslStream.Write(array);
                sslStream.Flush();
                client.Close();
                return true;
            }
            catch (System.Security.Authentication.AuthenticationException ex)
            {
                client.Close();
                return false;
            }
            catch (Exception e)
            {
                client.Close();
                return false;
            }
        }
        private static byte[] HexStringToByteArray(String DeviceID)
        {
            byte[] deviceToken = new byte[DeviceID.Length / 2];
            for (int i = 0; i < deviceToken.Length; i++)
                deviceToken[i] = byte.Parse(DeviceID.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
            return deviceToken;
        }

        public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;
            else // Do not allow this client to communicate with unauthenticated servers.
                return false;
        }

四、部署APP

開啟 \platform\ios\filename.xcodeproj,點選【capabilities】開啟Push Notifications 


五、結論

因為模擬器上無法顯示推播所以沒辦法展示推播成功的圖片,但部署在Iphone手機上確實收到推播訊息,希望這篇文章有幫助到各位喔~


參考資料: