顯示具有 教學 標籤的文章。 顯示所有文章
顯示具有 教學 標籤的文章。 顯示所有文章

2015年12月30日 星期三

[Qt] JavaScript / Qt 與Facebook Login SDK 使用

在完成這個專案之前,花了很多時間在research Facebook Login SDK,說實話實在是有點難搞懂

畢竟要透過Qt來使用JavaScript,不是這麼多範例可以參考,所以後來就改變策略-------

在html上寫JS然後透過QWebView+QUrl來呼叫網頁達成目的!

需要知道的

1.JavaScript如何轉址

2.JavaScript的FB login SDK流程如何

3.如何取得response與accessToken(最重要!App通行證)

//

第一個網址:

我們需要自動轉址到Facebook Login畫面

第二個網址:

Login成功以後,需要轉址到第二個網址(如果都轉址到第一個網址,會造成無窮迴圈)

取得accessToken

第三個網址:

為了讓Qt取得accessToken我們必須要在網址上面動手腳,

也就是帶accessToken在網址上,因此第二網址再轉址到第三網址


以上為說明
-----------------------------------------------------------------------------------------------------------------------

1.test1.html

<!DOCTYPE html>
<html>
<head>
<title>Facebook Login</title>
<meta charset="UTF-8">
</head>
<body>
<p>測試文字</p>
<script>

var url2 = 'https://www.facebook.com/dialog/oauth?client_id=你的App ID&scope=email,user_birthday&redirect_uri=第二網址';
setTimeout("location.href=url2",1);//轉址目的地,自動轉址秒數
console.log('test2');

</script>
<div id="status">
</div>

</body>
</html>

2.test2.html

<!DOCTYPE html>
<html>
<head>
<title>Facebook Login JavaScript Example</title>
<meta charset="UTF-8">
</head>
<body>
<p>123</p>
<script>

<!--開頭initial-->
var url;


  window.fbAsyncInit = function() {
    // init the FB JS SDK
  FB.init({
    appId      : '你的ID',
    cookie     : true,  // enable cookies to allow the server to access
                        // the session
    xfbml      : true,  // parse social plugins on this page
    version    : 'v2.2' // use version 2.2
  });


  FB.login(function(response) {
  console.log('in FB.login');
    if (response.authResponse) {
     console.log('Welcome!  Fetching your information.... ');
     FB.api('/me', function(response) {
       console.log('Good to see you, ' + response.name + '.');
     });
    } else {
     console.log('User cancelled login or did not fully authorize.');
    }
});

  // This is called with the results from from FB.getLoginStatus().
  function statusChangeCallback(response) {
    console.log('in function: statusChangeCallback');
    console.log(response);
    // The response object is returned with a status field that lets the
    // app know the current login status of the person.
    // Full docs on the response object can be found in the documentation
    // for FB.getLoginStatus().
    if (response.status === 'connected') {
      // Logged into your app and Facebook.
 var uid = response.authResponse.userID;
      var accessToken = response.authResponse.accessToken;
 console.log(accessToken);
 //alert(accessToken);

testAPI(response);
 //document.write(accessToken);
 //testAPI(response);
 document.getElementById('status').innerHTML = 'Entry success';
    } else if (response.status === 'not_authorized') {
      // The person is logged into Facebook, but not your app.
 FB.login();
      document.getElementById('status').innerHTML = 'Please log ' +
        'into this app.';
    } else {
      // The person is not logged into Facebook, so we're not sure if
      // they are logged into this app or not.
 console.log('in unknown');
      document.getElementById('status').innerHTML = 'facebook login failed';
    }
  }

  // This function is called when someone finishes with the Login
  // Button.  See the onlogin handler attached to it in the sample
  // code below.
  function checkLoginState() {
    console.log('in checkLoginState');
    FB.getLoginStatus(function(response) {
      statusChangeCallback(response);
    });
  }

  FB.getLoginStatus(function(response) {
    console.log('in getLoginStatus');
    statusChangeCallback(response);
  });

  };



  // Load the SDK asynchronously
  (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/sdk.js";
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));

  // Here we run a very simple test of the Graph API after login is
  // successful.  See statusChangeCallback() for when this call is made.

  function testAPI(response) {
  /*
    console.log('Welcome!  Fetching your information.... ');
    FB.api('/me', function(response) {
      console.log('Successful login for: ' + response.name);
      document.getElementById('status').innerHTML =
        'Thanks for logging in, ' + response.name + '!';
    });
*/

var accessToken = response.authResponse.accessToken;
  url = "第三個網址(轉址的)?" + accessToken;
setTimeout("location.href=url",1);
  }

window["checkLoginState()"];
console.log('get login');
</script>



<!--
<script src="http://connect.facebook.net/zh_TW/all.js"></script>
  Below we include the Login Button social plugin. This button uses
  the JavaScript SDK to present a graphical Login button that triggers
  the FB.login() function when clicked.
-->

<!--
<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>
-->
<div id="status">
</div>

</body>
</html>

3.test3.html

<!DOCTYPE html>
<html>
<head>
<title>Facebook Login</title>
<meta charset="UTF-8">
</head>
<body>
<p>test3</p>
<script>
 //URL
    var url = location.href;
   
    //取得問號之後的值
    var temp = url.split("?");

    //將值再度分開
    var vars = temp[1].split("&");

    //一一顯示出來
    for (var i = 0; i < vars.length; i++) {
     alert(vars[i]);
    };

 

</script>
<div id="status">
</div>

</body>
</html>


可以看到test.html是轉址透過

https://www.facebook.com/dialog/oauth?

+

client_id=你申請的App ID(數字)

+

&scope=email,user_birthday(你要的權限有多少)

+

&redirect_uri=轉址一號站


第二部分則是

facebook SDK

:

// Load the SDK asynchronously
  (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/sdk.js";
    fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));





大概內容就是三種情況

1.connected : 已經連線,成功登入(取得accessToken)

2.unauthorized: 已經登入,但是沒有允許權限開啟(呼叫login() )

3.unknown:尚未登入(呼叫login() )

如果輸入都正確就會取得accessToken,但這時候要仍然是在網頁上面要怎樣讓Qt去取得呢?

在Qt的QWebView裡面有一個Signal--urlchanged(),這意思是甚麼呢?就是當網址有所變動時(轉

址)會發送信號,因此我們就可以透過這個signal去取得轉址後的網址(當然是有帶accessToken)

如此,就達成目的了!

*******************************************************************************

照這方法做一定會遇到無法轉址的問題

"無法xxxxx,畫布...."之類的錯誤訊息







要把你要轉址的網址(可以超過一個)放在valid OAuth redirect URL這一欄裡面,這樣才能夠正常

運作!

the END

2014年10月28日 星期二

[Android] Navigation Drawer的使用(簡易)

如果有看過Facebook app左側或右側可以拉出來的側邊欄, 那麼你已經看過Navigation Drawer了

不過在實際使用上不是那麼的容易(不然就不用寫教學了), 這邊我也研究了兩次,第一次失敗(覺

得太複雜就先做別的),第二次也就是這次才成功。決定把這個有點難的功能寫下來,當然也不

能說是全部都搞懂,就是把會的寫下來,以免以後忘掉。


這個是完成圖-也就是在手機上左側往右邊拉會出現這樣

的ListView選單。要多少選項可以自行調整(超過螢幕的

長度我就沒有測試了),選項一從編號0開始(所以用switch

case 搭配抓取該item的position就可以應用了)

















已經大概把Navigation Drawer大概介紹完了(詳細介紹可以找網路),先上程式碼:

(程式碼是下載 TonyCube來修改的)

Step1:

private void InitDrawer(){

fragmentManager = getFragmentManager();

layDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
lstDrawer = (ListView) findViewById(R.id.lst_drawer);

layDrawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);

mTitle = mDrawerTitle = getTitle();
drawerToggle = new ActionBarDrawerToggle(
this,
layDrawer,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close) {

@Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
//getActionBar().setTitle(mTitle);
      //這邊可以改string內容,關閉時上方標題會改變,如果沒有要標題就不能用這一行
}

@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
//getActionBar().setTitle(R.string.drawer_open);
//這邊可以改string內容,開啟時上方標題會改變,如果沒有要標題就不能用這一行
}
};
drawerToggle.syncState();

layDrawer.setDrawerListener(drawerToggle);
}

首先一定是初始化,因此你需要宣告:

   private ActionBarDrawerToggle drawerToggle;
   private CharSequence mDrawerTitle;
   private CharSequence mTitle;
   private String[] drawer_menu;

以免等等會出現錯誤。

findByViewId的部分就是讓程式知道你要的那個元件是在xml裡面的哪一個,

setDrawerShadows的部分很明顯的就是設定陰影(這邊我沒有修改)

mTitle/Title的部分,如果你前面有設定隱藏title,那麼請把這一行+下面setTitle註解掉,因為會出錯

onDrawerOpen/onDrawerClose就是當側邊欄被拉開時/關閉時的動作,裡面可以自由發揮

setDrawerListener就是設一個監聽器,可以隨時抓取動作


Step2:

private void InitDrawerList(){
drawer_menu = this.getResources().getStringArray(R.array.drawer_menu);
//ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.drawer_list_item, drawer_menu);

List<HashMap<String,String>> lstData = new ArrayList<HashMap<String,String>>();
//多少個item@String Array => for跑幾次
for (int i = 0; i <drawer_menu.length; i++) {
HashMap<String, String> mapValue = new HashMap<String, String>();
//mapValue.put("icon", Integer.toString(R.drawable.ic_launcher));
              //要圖示的話才需要加這一行
mapValue.put("title", drawer_menu[i]);
lstData.add(mapValue);
}
SimpleAdapter adapter = new SimpleAdapter(this, lstData, R.layout.drawer_list_item2, new String[]{"icon", "title"}, new int[]{R.id.imgIcon, R.id.txtItem});
lstDrawer.setAdapter(adapter);

//側選單點選監聽器
lstDrawer.setOnItemClickListener(new DrawerItemClickListener());
}

這部分是在設定選項,你有多少個選項for就跑多少次(當然在res-value-Strings-StringArray裡面要

先設定好),旁邊圖示我沒有使用,當然要使用的話也是可以就把mapValue那一行重新恢復即

可。一樣設定監聽器,讓使用者點選時可以馬上反應。

Step3:

 private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }
   
private void selectItem(int position) {
        Fragment fragment = null;
        FragmentTransaction fragmentTransaction;
        switch (position) {
case 0:
fragment = new Config();
//layDrawer.closeDrawer(lstDrawer);
info_txv.setVisibility(View.INVISIBLE);
main_txv.setVisibility(View.INVISIBLE);
imageView.setVisibility(View.INVISIBLE);
       fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.Linear_left_drawer, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.commit();
break;

case 1:
InitPopup_IP_setting();

break;

case 2:
Self_Test();
break;

default:
//還沒製作的選項,fragment 是 null,直接返回
return;
}

        layDrawer.closeDrawer(lstDrawer);
    }

這部分監聽器會監聽使用者點選哪個item,會收到position是哪一個,然後再使用selectItem這個函

式處理,這邊使用switch...case。第一個選項是使用一個fragment去取代目前的fragment,由於

fragmentTransaction.addToBackStack(null)無法回去到原本的fragment,因此這個選項有回不去的

風險,請小心使用。第二個選項這邊是設定AlertDialog(),跟NavigationDrawer不相關,不重要因此

就不贅述,第三個選項亦同,default,或是任何你還沒設定的選項請使用return而不是break,否則就

會看到你的app掛點。最後記得要使用closeDrawer()來關閉NavigationDrawer。



NavigationDrawer大概就是這幾部分,然後如果要新增一個頁面(就是讓你點選一個選項會跳到

另一個頁面)的話,在res-layout這邊新增一個xml檔,在src裡面新增一個java檔*如下圖



這樣就可以連結囉!


以上就是NavigationDraw的小心得。 End