
ตัวอย่างนี้เป็นแนวทางสำหรับคนที่ต้องการเขียน API ของ Line SDK ส่วนของ Line Login ร่วมกับแอพพลิเคชันระบบปฏิบัติการ Android
Line ได้เปิด Social API ให้กับนักพัฒนาแอพพลิเคชันและเกม ออกมา 2 ตัวคือ Line Login และ Message API ครับซึ่งตัวอย่างนี้เราจะใช้ Line Login ก่อน ซึ่งการทำงานก็ไม่มีอะไรมากครับ คือการ Authentication เข้าแอพพิลเคชัน หรือ เกมเหมือนการใช้ Facebook Login นั่นแหละ แต่เป็นการใช้ Line แทนนั่นเองครับ
ตัวอย่างจาก Line developer Portal



การสมัคร Line Developer
ไปที่ Line Developer (https://developers.line.me) ทำการสมัครเป็นนักพัฒนาครับ

ใช้ Line ID หรือ Email ของเราในการสมัครเป็นนักพัฒนา เปิดเมลเพื่อ Activated ยืนยันตัวตนครับ ระบบจะพาเรากลับไปยัง Developer Portal ใหม่


ให้เราเปิดใช้งาน Social API ของ Line Login

ไปเลือกที่ LINE Login ครับ

เลือกเป็น WEB และ NATIVE_APP ไปเลยเผื่อจะต่อยอดส่วนของ เว็บไซต์ด้วย หลังจากนั้นไปที่เมนู Download SDK เลือก LineSDK_android_4.0.0.zip ครับ ดาวน์โหลดมาแตกไฟล์ zip ให้เรียบร้อย

เราจะได้ Channel ID มาด้วย

คราวนี้เราก็มาออกแบบแอพพิลเคชันของเราบ้างดีกว่า เปิด Android Studio ขึ้นมาครับ สร้าง Basic Activity ใหม่ เลือกโหมดของ Solution เป็น Projects ครับไปยัง Folder ชื่อ libs นำไฟล์ .arr ของ Line SDK ไปวางในนั้นซะ

เปิดโหมด Project หา libs แล้วนำไฟล์ .aar ไปวาง

ตามตัวอย่าง

ทำการเปิด buil.Gradle ส่วนของ Project ขึ้นมาตั้งค่าตามนี้
allprojects {
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
}
ให้มีการ Flat ไปยัง Directory ที่ชื่อว่า “libs” หลังจากนั้นเปิด Gradle ของส่วน Module ขึ้นมา แก้ไขดังนี้ใน dependencies
compile(name:'line-sdk-4.0.0', ext:'aar')
ไฟล์จะเป็นแบบนี้
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.daydev.lineapidev"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support:design:25.2.0'
compile(name:'line-sdk-4.0.0', ext:'aar')
testCompile 'junit:junit:4.12'
}
ไปที่ AndroidManiFest.xml เปิด Permission ของ Internet ครับ
<uses-permission android:name="android.permission.INTERNET" />
ต่อมาเรามาออกแบบหน้าจอ XML ของ content_activity.xml ดังนี้
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_main"
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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.daydev.lineapidev.MainActivity"
tools:showIn="@layout/activity_main">
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login with LINE"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:background="@color/colorPrimary"
android:textColor="@android:color/background_light" />
<Button
android:id="@+id/browser_login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Browser Login"
android:layout_marginTop="45dp"
android:layout_below="@+id/login_button"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@color/colorPrimary"
android:textColor="@android:color/background_light" />
</RelativeLayout>

ในการทำงานเราจะมีการแบ่ง Class ของ Activity เพิ่มมาคือส่วนของ Post Login และการเก็บค่า Channel ID ซึ่งเก็บใน strings.xml ก็ได้แต่ตัวอย่างเก็บไว้ใน Class ชื่อ Constants
ทำการสร้าง Java Class มาใหม่ใน Package ของเรา

ตั้งชื่อว่า Constants

ใน Class Constants.java เก็บ Channel ID ของเราครับ
package com.daydev.lineapidev;
/**
* Created by banyapon on 3/5/2017 AD.
*/
public class Constants {
// Set this value to your Channel ID
public static final String CHANNEL_ID = "1XXXXXXXX4";
}
ไปที่ https://developers.line.me/ba/tech/ ส่วนของ Technical Configuration ทำการใส่ package name และ Hashkey ของ แอพพลิเคชันเราลงไป

Hash Key ให้ใส่ใน Android Package Signature วิธีการก็หาเอาใน Google ครับส่วนของ OS X ก็ข้างล่าง

เพิ่ม Activity ใหม่ขึ้นมาครับชื่อว่า PostLoginActivity


ออกแบบหน้าจอ content_post_login.xml ดังนี้
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_post_login"
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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.daydev.lineapidev.PostLoginActivity"
tools:showIn="@layout/activity_post_login">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/nameLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/displayNameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="TextView"
android:textAlignment="center"
android:textSize="24sp"
android:textStyle="normal|bold"
tools:text="Name" />
</LinearLayout>
<LinearLayout
android:id="@+id/imageLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/nameLayout"
android:orientation="vertical">
<ImageView
android:id="@+id/profileImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
app:srcCompat="@android:color/background_light" />
</LinearLayout>
<LinearLayout
android:id="@+id/userDataLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imageLayout"
android:orientation="vertical">
<LinearLayout
android:id="@+id/userDataLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imageLayout"
android:orientation="vertical">
<TextView
android:id="@+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="User ID:"
android:textSize="18sp"
android:textStyle="normal|bold" />
<TextView
android:id="@+id/userIDField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:id="@+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status Message:"
android:textAlignment="textStart"
android:textSize="18sp"
android:textStyle="normal|bold" />
<TextView
android:id="@+id/statusMessageField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:id="@+id/textView13"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Access Token:"
android:textSize="18sp"
android:textStyle="normal|bold" />
<TextView
android:id="@+id/accessTokenField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/buttonlayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/userDataLayout"
android:orientation="vertical">
<Button
android:id="@+id/profileButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Get Profile" />
<Button
android:id="@+id/refreshButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Refresh Token" />
<Button
android:id="@+id/verifyButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Verify Token" />
<Button
android:id="@+id/logoutButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Logout" />
</LinearLayout>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
สร้าง Resource ใหม่ขึ้นมาชื่อว่า profile_dialog.xml


โดยมีโครงสร้าง xml ดังนี้
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/loadingPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</LinearLayout>
<LinearLayout
android:id="@+id/profileContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="invisible">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_green_light"
android:text="@string/profile_screen_label"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="normal|bold" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/profile_display_name_label"
android:textSize="14sp"
android:textStyle="normal|bold" />
<TextView
android:id="@+id/profileName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/profile_mid_label"
android:textSize="14sp"
android:textStyle="normal|bold" />
<TextView
android:id="@+id/profileMid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/profile_status_message_label"
android:textSize="14sp"
android:textStyle="normal|bold" />
<TextView
android:id="@+id/profileMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/profile_image_label"
android:textSize="14sp"
android:textStyle="normal|bold" />
<TextView
android:id="@+id/profileImageUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

กำหนดค่า Strings.xml กันหน่อย ตามตัวอย่างเลย
<resources>
<string name="app_name">เปิดสาขา DA ที่ DPU</string>
<string name="action_settings">Settings</string>
<string name="title_activity_post_login">PostLoginActivity</string>
<string name="profile_screen_label">User Profile</string>
<string name="profile_display_name_label">Display Name:</string>
<string name="profile_mid_label">MID:</string>
<string name="profile_status_message_label">Status Message:</string>
<string name="profile_image_label">Profile Image URL:</string>
<string name="no_profile_image_set">Profile Image Not Set</string>
</resources>
ต่อมาให้สร้าง Action ของ MainActivity.java ส่วนของปุ่มในการ Login ทั้งสองดังนี้
final Button a2aButton = (Button) findViewById(R.id.login_button);
a2aButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
// App to App Login
Intent LoginIntent = LineLoginApi.getLoginIntent(v.getContext(), Constants.CHANNEL_ID);
startActivityForResult(LoginIntent, REQUEST_CODE);
} catch (Exception e) {
Log.e("ERROR", e.toString());
}
}
});
final Button browserLoginButton = (Button) findViewById(R.id.browser_login_button);
browserLoginButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
// Browser Login
Intent LoginIntent = LineLoginApi.getLoginIntentWithoutLineAppAuth(v.getContext(), Constants.CHANNEL_ID);
startActivityForResult(LoginIntent, REQUEST_CODE);
} catch (Exception e) {
Log.e("ERROR", e.toString());
}
}
});
โดยมีเมธอดใหม่เพิ่มเข้าไปคือ
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != REQUEST_CODE) {
Log.e("ERROR", "Unsupported Request");
return;
}
LineLoginResult result = LineLoginApi.getLoginResultFromIntent(data);
switch (result.getResponseCode()) {
case SUCCESS:
Intent transitionIntent = new Intent(this, PostLoginActivity.class);
transitionIntent.putExtra("line_profile", result.getLineProfile());
transitionIntent.putExtra("line_credential", result.getLineCredential());
startActivity(transitionIntent);
break;
case CANCEL:
Log.e("ERROR", "LINE Login Canceled by user!!");
break;
default:
Log.e("ERROR", "Login FAILED!");
Log.e("ERROR", result.getErrorData().toString());
}
}
ภาพรวมไฟล์ MainActivity.java เป็นดังนี้
package com.daydev.lineapidev;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import com.linecorp.linesdk.auth.LineLoginApi;
import com.linecorp.linesdk.auth.LineLoginResult;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
final Button a2aButton = (Button) findViewById(R.id.login_button);
a2aButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
// App to App Login
Intent LoginIntent = LineLoginApi.getLoginIntent(v.getContext(), Constants.CHANNEL_ID);
startActivityForResult(LoginIntent, REQUEST_CODE);
} catch (Exception e) {
Log.e("ERROR", e.toString());
}
}
});
final Button browserLoginButton = (Button) findViewById(R.id.browser_login_button);
browserLoginButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
// Browser Login
Intent LoginIntent = LineLoginApi.getLoginIntentWithoutLineAppAuth(v.getContext(), Constants.CHANNEL_ID);
startActivityForResult(LoginIntent, REQUEST_CODE);
} catch (Exception e) {
Log.e("ERROR", e.toString());
}
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != REQUEST_CODE) {
Log.e("ERROR", "Unsupported Request");
return;
}
LineLoginResult result = LineLoginApi.getLoginResultFromIntent(data);
switch (result.getResponseCode()) {
case SUCCESS:
Intent transitionIntent = new Intent(this, PostLoginActivity.class);
transitionIntent.putExtra("line_profile", result.getLineProfile());
transitionIntent.putExtra("line_credential", result.getLineCredential());
startActivity(transitionIntent);
break;
case CANCEL:
Log.e("ERROR", "LINE Login Canceled by user!!");
break;
default:
Log.e("ERROR", "Login FAILED!");
Log.e("ERROR", result.getErrorData().toString());
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
ส่วนของ PostLoginActivity.java คือคำสั่งต่อไปนี้
package com.daydev.lineapidev;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.linecorp.linesdk.LineAccessToken;
import com.linecorp.linesdk.LineApiResponse;
import com.linecorp.linesdk.LineCredential;
import com.linecorp.linesdk.LineProfile;
import com.linecorp.linesdk.api.LineApiClient;
import com.linecorp.linesdk.api.LineApiClientBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class PostLoginActivity extends AppCompatActivity {
private LineApiClient lineApiClient;
// Method for preventing orientation changes during ASyncTasks
private void lockScreenOrientation(){
int currentOrientation = getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_PORTRAIT){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
// This method is used to reenable orientation changes after an ASyncTask is finished.
private void unlockScreenOrientation(){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
public static class ProfileDialogFragment extends DialogFragment {
private LineProfile profileInfo;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.profile_dialog, null);
TextView textview = (TextView) view.findViewById(R.id.profileName);
textview.setText(profileInfo.getDisplayName());
textview = (TextView) view.findViewById(R.id.profileMessage);
textview.setText(profileInfo.getStatusMessage());
textview = (TextView) view.findViewById(R.id.profileMid);
textview.setText(profileInfo.getUserId());
Uri pictureUrl = profileInfo.getPictureUrl();
textview = (TextView) view.findViewById(R.id.profileImageUrl);
// If the user's profile picture is not set, the picture url will be null.
if (pictureUrl != null) {
textview.setText(profileInfo.getPictureUrl().toString());
} else {
textview.setText(view.getContext().getResources().getString(R.string.no_profile_image_set));
}
view.findViewById(R.id.loadingPanel).setVisibility(View.GONE);
view.findViewById(R.id.profileContent).setVisibility(View.VISIBLE);
builder.setView(view);
builder.setPositiveButton("OK", null);
return builder.create();
}
public LineProfile getProfileInfo() {
return profileInfo;
}
public void setProfileInfo(LineProfile profileInfo) {
this.profileInfo = profileInfo;
}
}
public class ImageLoaderTask extends AsyncTask<String, String, Bitmap> {
final static String TAG = "ImageLoaderTask";
protected void onPreExecute(){
lockScreenOrientation();
}
protected Bitmap doInBackground(String... strings) {
Bitmap bitmap = null;
try {
URL url = new URL(strings[0]);
bitmap = BitmapFactory.decodeStream((InputStream) url.getContent());
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
return bitmap;
}
protected void onPostExecute(Bitmap bitmap) {
ImageView profileImageView = (ImageView) findViewById(R.id.profileImageView);
profileImageView.setImageBitmap(bitmap);
unlockScreenOrientation();
}
}
public class RefreshTokenTask extends AsyncTask<Void, Void, LineApiResponse<LineAccessToken>> {
final static String TAG = "RefreshTokenTask";
protected void onPreExecute(){
lockScreenOrientation();
}
protected LineApiResponse<LineAccessToken> doInBackground(Void... params) {
return lineApiClient.refreshAccessToken();
}
protected void onPostExecute(LineApiResponse<LineAccessToken> response) {
if (response.isSuccess()) {
String updatedAccessToken = lineApiClient.getCurrentAccessToken().getResponseData().getAccessToken();
// Update the view
TextView accessTokenField = (TextView) findViewById(R.id.accessTokenField);
accessTokenField.setText(updatedAccessToken);
Toast.makeText(getApplicationContext(), "Access Token has been refreshed.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Could not refresh the access token.", Toast.LENGTH_SHORT).show();
Log.e(TAG, response.getErrorData().toString());
}
unlockScreenOrientation();
}
}
public class VerifyTokenTask extends AsyncTask<Void, Void, LineApiResponse<LineCredential>> {
final static String TAG = "VerifyTokenTask";
protected void onPreExecute(){
lockScreenOrientation();
}
protected LineApiResponse<LineCredential> doInBackground(Void... params) {
return lineApiClient.verifyToken();
}
protected void onPostExecute(LineApiResponse<LineCredential> response) {
if (response.isSuccess()) {
StringBuilder toastStringBuilder = new StringBuilder("Access Token is VALID and contains the permissions ");
for (String temp : response.getResponseData().getPermission()) {
toastStringBuilder.append(temp + ", ");
}
Toast.makeText(getApplicationContext(), toastStringBuilder.toString(), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Access Token is NOT VALID", Toast.LENGTH_SHORT).show();
}
unlockScreenOrientation();
}
}
public class GetProfileTask extends AsyncTask<Void, Void, LineApiResponse<LineProfile>> {
private ProfileDialogFragment fragment;
final static String TAG = "GetProfileTask";
protected void onPreExecute(){
lockScreenOrientation();
}
protected LineApiResponse<LineProfile> doInBackground(Void... params) {
return lineApiClient.getProfile();
}
protected void onPostExecute(LineApiResponse<LineProfile> apiResponse) {
if(apiResponse.isSuccess()) {
ProfileDialogFragment newFragment = new ProfileDialogFragment();
newFragment.setProfileInfo(apiResponse.getResponseData());
newFragment.show(getFragmentManager(), null);
unlockScreenOrientation();
} else {
Toast.makeText(getApplicationContext(), "Failed to get profile.", Toast.LENGTH_SHORT).show();
Log.e(TAG, "Failed to get Profile: " + apiResponse.getErrorData().toString());
}
}
}
public class LogoutTask extends AsyncTask<Void, Void, LineApiResponse> {
final static String TAG = "LogoutTask";
protected void onPreExecute(){
lockScreenOrientation();
}
protected LineApiResponse doInBackground(Void... params) {
return lineApiClient.logout();
}
protected void onPostExecute(LineApiResponse apiResponse){
if(apiResponse.isSuccess()){
Toast.makeText(getApplicationContext(), "Logout Successful", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Logout Failed", Toast.LENGTH_SHORT).show();
Log.e(TAG, "Logout Failed: " + apiResponse.getErrorData().toString());
}
unlockScreenOrientation();
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_login);
LineApiClientBuilder apiClientBuilder = new LineApiClientBuilder(getApplicationContext(), Constants.CHANNEL_ID);
lineApiClient = apiClientBuilder.build();
// Profile Button Click Listener
final Button profileButton = (Button) findViewById(R.id.profileButton);
profileButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new GetProfileTask().execute();
}
});
// Refresh Button Click Listener
final Button refreshButton = (Button) findViewById(R.id.refreshButton);
refreshButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new RefreshTokenTask().execute();
}
});
// Verify Button Click Listener
final Button verifyButton = (Button) findViewById(R.id.verifyButton);
verifyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new VerifyTokenTask().execute();
}
});
// Logout Button Click Listener
final Button logoutButton = (Button) findViewById(R.id.logoutButton);
logoutButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new LogoutTask().execute();
finish();
}
});
// Get the intent so that we can get information from the previous activity
Intent intent = getIntent();
LineProfile intentProfile = intent.getParcelableExtra("line_profile");
LineCredential intentCredential = intent.getParcelableExtra("line_credential");
ImageView profileImageView = (ImageView) findViewById(R.id.profileImageView);
Uri pictureUrl = intentProfile.getPictureUrl();
if (pictureUrl != null) {
Log.i("PostLoginActivity", "Picture URL: " + pictureUrl.toString());
new ImageLoaderTask().execute(pictureUrl.toString());
}
TextView profileText;
profileText = (TextView) findViewById(R.id.displayNameField);
profileText.setText(intentProfile.getDisplayName());
profileText = (TextView) findViewById(R.id.userIDField);
profileText.setText(intentProfile.getUserId());
profileText = (TextView) findViewById(R.id.statusMessageField);
profileText.setText(intentProfile.getUserId());
profileText = (TextView) findViewById(R.id.accessTokenField);
profileText.setText(intentCredential.getAccessToken().getAccessToken());
}
}
เพิ่ม Activity state ของ AndroidManiFest.xml ดังนี้
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.daydev.lineapidev">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".PostLoginActivity" android:label="User Information"></activity>
</application>
</manifest>
ทดสอบโดยการ Run ตัวแอพพลิเคชันของเราแล้วทำการ Login ด้วย Line ดูเราจะพบว่า เราจะขอสิทธิในการ Login และ Permission ของ User ใน Line จากแอพพลิเคชัน Line ของเราได้แล้ว




จะเห็นว่าการออกแบบ Line APIต่อไปก็คือการ Identity Thief มากขึ้นแบบที่ แอพขำขันทำกัน คำถามคือถ้าผมบอกว่า ขอให้เชื่อใจผม เค้าจะยอมไหมนะ เพราะกระบวนการนี้ได้มาซึ่ง token ซึ่งผมอาจจะแอบเก็บไว้ทำอะไรก็ได้ทีหลังอยู่ดี
ใครขี้เกียจเขียน Code เองมี git ของ Line ให้นะเค้าทำไว้ https://github.com/line/line-sdk-starter-android-v2




