2013-07-10

Android跨平台應用(一) - 運用AD登入

人永遠是不會滿足的,而且老闆更不容易滿足,這是真的!QQ"

老闆不滿足,他也不會讓你滿足(薪水),所以當一個稱職的員工,就要盡力滿足他

好了,廢話說完了,再來進入正題.....

當Android原生寫到一定程度時通常都會想還有什麼可以應用

跨平台應用是會被用到也很常會被使用到的,所以就來往這方式研究

這次來研究如果運用在公司內很常見的AD來登入自己開發的Android應用程式

AD是什麼?AD(Active Directory)說明在這裡

也可以在左邊用Active Directory進維基百科查詢,這裡就不再說明

這樣的目的當然是為了SSO(Single-Sign-On單一登入),不用重覆建立登入資料

看起來好像很方便,實際上.........也是很方便,哈!而且如果不這樣做,老闆是不會滿足的xd

先來說一下原理好了:




佈局:

1.Android應用程式放在Android手機內(廢話..)

2.Web Service放在可對外的Server主機內

3.AD Server放在公司內部Server主機內


說明:

我的設計是手機端經由Web Service傳送帳號密碼給AD Server進行驗證

其實也是可以直接傳給AD Server進行驗證,但為什麼要這樣設計呢?

因為兩個原因:1.可以加密確保帳密的安全
                            2.AD Server IP位置改變時不用重新修改Android應用程式,使用者還要更新
                               只需修改Web Service對應的AD Server 的IP位置即可

光原因二就有必要用這種設計方式了,因為AD Server IP改變後如果使用者沒有更新新的apk檔,基本上這個程式就會出錯,所以中間加一個Web Service彈性是比較高的

再來看一下程式碼:

Web Service
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Data.OleDb;
using System.Collections;
using System.Data;
using System.DirectoryServices;

/// <summary>
/// Search 的摘要描述
/// </summary>
[WebService(Namespace = "http://WebServiceForApp/")]//必須和android手機內的Namespace對應
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// 若要允許使用 ASP.NET AJAX 從指令碼呼叫此 Web 服務,請取消註解下一行。
// [System.Web.Script.Services.ScriptService]
public class Search : System.Web.Services.WebService {
    string _path;
    string _filterAttribute;

    public OleDbConnection Conn = new OleDbConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);

    public Search () {

        //如果使用設計的元件,請取消註解下行程式碼 
        //InitializeComponent(); 
    }

    [WebMethod]
    public bool Verification(string username,string pwd)
    {
        string domain = "192.168.2.211";//AD Server IP位置
        bool V = true;
        _path = "LDAP://" + domain;
        string domainAndUsername = domain + @"\" + username;
        DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);

        try
        {
            //Bind to the native AdsObject to force authentication.            
            object obj = entry.NativeObject;
            DirectorySearcher search = new DirectorySearcher(entry);

            search.Filter = "(SAMAccountName=" + username + ")";
            search.PropertiesToLoad.Add("cn");
            SearchResult result = search.FindOne();

            //帳號是:it01
            //回覆驗證資料,無為null
            //有Data內容會是這個樣子:LDAP://192.168.2.211/CN=it01,OU=資訊部,OU=管理處,DC=goldjoint,DC=com
            if ((result == null))
            {
                V = false;
            }

            //Update the new path to the user in the directory.
            _path = result.Path;
            _filterAttribute = (string)result.Properties["cn"][0];

        }
        catch (Exception ex)
        {
            //throw new Exception("Error authenticating user. " + ex.Message);
            V = false;
        }


        return V;
    }
}


注意:
手機端我是有使用到ksoap2
所以必須先掛載ksoap2的jar檔進來,以便連結Web Service
網路上掛載的方法很多都有寫,所以這裡就不再重覆,請先掛載。



Android手機端
void WebData()
{
//從網路上獲取資料
String NAMESPACE = "http://WebServiceForApp/";//必須和Web Service內的Namespace對應
String URL = "http://你的WebService位置/AppWebService/Search.asmx";
String SOAP_ACTION = "http://WebServiceForApp/Verification";//NAMESPACE+WebService METHOD_NAME
String METHOD_NAME = "Verification";  

//Data
SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME); 
PropertyInfo sayHelloPI = new PropertyInfo();
sayHelloPI.setName("username");//加入帳號
sayHelloPI.setValue(id);
sayHelloPI.setType(String.class);
Request.addProperty(sayHelloPI);

PropertyInfo sayHelloPI2 = new PropertyInfo();
sayHelloPI2.setName("pwd");//加入密碼
sayHelloPI2.setValue(pw);
sayHelloPI2.setType(String.class);
Request.addProperty(sayHelloPI2);

//Request.addProperty("ID",strSearch);
SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
soapEnvelope.dotNet=true;
soapEnvelope.setOutputSoapObject(Request);
HttpTransportSE aht=new HttpTransportSE(URL);
//aht.debug=true;
try {
aht.call(SOAP_ACTION, soapEnvelope);
//SoapObject result = (SoapObject)soapEnvelope.getResponse();
SoapPrimitive result = (SoapPrimitive)soapEnvelope.getResponse();//單純Data用這個

//存入回傳資料(String Check存入True or False)
check = result.toString();//Check就能拿來檢查是否有AD驗證過了


} catch (SoapFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}	
}

說明:

有幾個重點要注意:
1.Namespace對應,Web Service和Android手機端的Namespace一定要相同
2.我是有另外專為這個Web Service在IIS上新增一個網站做控管(這點好像不是什麼重點xd)
3.加不加密看狀況,我是走一般網路的80 port,也能走其他的port,但要另外開放和設定
   應用程式封裝成apk檔有一定的安全性了,因為Android 2.3.3以後的版本Google有加入亂碼
   ,程式碼會重排,所以要知道的人還是會知道(應該是自己人xd),如果還是要小心一點可以
   加密,反正可以在Web Service解密就好,這樣就能再送AD Server驗證,本人完全沒加密xd

以上程式碼是可以RUN的,而且也在RUN中,所以如果你不能RUN請留言我幫您看一下為什麼不能RUN。
 
我只取出部份的程式碼,其他部份可能要自己拼湊,不要跟我要全部的程式碼,因為那不是我的,所以我不能給你。


Java Script Window Print-另開視窗方式列印

Web表單設計時還蠻常需要用到列印的,一般都會用Reporting Service

這裡教你用Java Script的方式,另開一個視窗列印表單,順便幫自己記錄程式碼^^


先用DIV框定範圍
<div id="print" align="center">
  表單內HTML程式碼...
 .
 .
 .
 </div>


在Button加入列印OnClientClick事件
<asp:Button ID="Button7" runat="server" Text="列印" OnClientClick="myPrint(document.getElementById('print'));return false;" />


加入JavaScript列印事件
<script type="text/javascript">
        function myPrint(obj) {
            //打開一个新窗口newWindow
            var newWindow = window.open("打印窗口", "_blank");
            //要打印的div的内容
            var docStr = obj.innerHTML;
            newWindow.document.write('<div align="center"><asp:Label ID="lb_printTitle" runat="server" Font-Size="X-Large" style="font-family: 微軟正黑體; font-weight: 700" Text="部門領用統計表"></asp:Label></div>');
            //打印内容寫入newWindow文檔
            newWindow.document.write(docStr);
            //關閉文檔
            newWindow.document.close();
            //調用打印機
            newWindow.print();
            //關閉newWindow頁面
            newWindow.close();
        }
     </script>


畫面(瀏覽器:IE10)
表單

另開列印視窗


注意
因為另開視窗是一個全新的視窗,所以第一次用可能會發現為什麼格式什麼全跑了
那是因為CSS沒有一起過去,所以在newWindow.document.write(.......)要把CSS一起
傳過去,不然就是寫在表單中,這樣出現的表單才會和你想要的一樣。

2013-01-30

Android 手機資料庫(六) - 使用Transaction(交易)

在Activity使用新增、修改、刪除時,有時候都會遇到需要同時處理多筆資料的狀況

這時候如果用一般的寫法,如果在中間處理的資料出錯了,那麼資料就會不完整寫入資料庫了

怎麼辦呢?這個時候就需要用到Transaction(交易),Transaction在很多程式中都有用到

而且是一定會用到,所以我們下面就來看一下在Android系統中該怎麼使用Transaction交易

來達到多筆資料同時處理的目的,其實和其他程式一樣很簡單的。

如果您看過前幾篇資料庫的文章的話,應該會知道其中會有一段db = helper.getWritableDatabase();

只要在這個下面加入:db.beginTransaction();//建立交易

之後就可以正常的用db.insert、db.update等一般資料庫寫入

在最後面都寫完資料庫後得加入此程式碼:db.setTransactionSuccessful();//正式寫入資料庫中

然後我們一般會使用try{}catch{}來抓取出錯誤的訊息,只要在catch中加入db.endTransaction();//結束交易

只要在寫入的過程中有一個出錯了,交易就會中斷,以達到多筆資料同進同出,就這麼簡單

以上就是為您介紹在Android系統中怎麼使用Transaction的方法,謝謝。

2013-01-24

Android 實用程式碼片段(一) - 返回鍵退出(onKeyDown)、返回鍵退出確認

現在應用程式上應該都有按下返回鍵會詢問是否離開的訊息,但這是怎麼做到的呢?

下面為您介紹此實用程式碼:

public boolean onKeyDown(int keyCode, KeyEvent event) {//捕捉返回鍵
        if ((keyCode == KeyEvent.KEYCODE_BACK)) {   
        	ConfirmExit();//按返回鍵,則執行退出確認
        	return true;   
        }   
        return super.onKeyDown(keyCode, event);   
    }
    public void ConfirmExit(){//退出確認
    	AlertDialog.Builder ad=new AlertDialog.Builder(MyOpenDataActivity.this);
    	ad.setTitle("離開");
    	ad.setMessage("確定要離開?");
    	ad.setPositiveButton("是", new DialogInterface.OnClickListener() {//退出按鈕
			public void onClick(DialogInterface dialog, int i) {
				// TODO Auto-generated method stub
				MyOpenDataActivity.this.finish();//關閉activity
 
			}
		});
    	ad.setNegativeButton("否",new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int i) {
				//不退出不用執行任何操作
			}
		});
    	ad.show();//示對話框
    }

只要在onCreate之外加入上面這段程式碼,程式就會在該Activity加入按下返回鍵時的詢問。