DEV Community

Cover image for Use Line Front-end Framework (LIFF) to enrich your bot
Kenichiro Nakamura
Kenichiro Nakamura

Posted on

Use Line Front-end Framework (LIFF) to enrich your bot

Overview

In this article, I explain how to develop a web page by using Line Front-end Framework (LIFF) SDK and enrich your bot, as well as how to use CLI too for LIFF.

I re-use some code from line-liff-starter repository.
The final version is hosted at here

LIFF application

It's a just another html page with javascript with LIFF SDK, which is registered by using LIFF API to generate unique URL to be used in LINE app.

Prerequisites

※ Even though I use Microsoft Azure to host my page, you can host it anywhere.

Prepare the environment first

Create "Channel" in LINE Developer Portal

Create Messaging API channel in LINE Developer portal, and get channel and token keys.

Please copy and keep "Your user ID" too.

Create WebApps in Azure Portal

You can use Azure Portal to create a web app, but I use CLI this time for fun.

1. Install、Azure CLI, or you can also use "Cloud Shell" on Azure Portal.

2. If you use Cloud Shall, skip to step 4. Otherwise follow the steps to login.



az login


Enter fullscreen mode Exit fullscreen mode

3. Follow the instruction on the screen to complete logging in.

4. Make sure you use right Azure Subscription in case you have some.



az account list
az account set -s 'subscription id'
az account show


Enter fullscreen mode Exit fullscreen mode

5. Create resource group. I created "lineliffsample" resource group in East Japan.



az group create -n lineliffsample -l japaneast


Enter fullscreen mode Exit fullscreen mode

6. Next, create a application service plan and a WebApps to host LIFF application.



az appservice plan create -n lineliffappplan -g lineliffsample --sku F1
az webapp create -n <unique name for WebApps> -g lineliffsample -p lineliffappplan


Enter fullscreen mode Exit fullscreen mode

7. Configure the WebApps to enable git deploy.



az webapp deployment user set --user-name <username> --password <password>
az webapp deployment source config-local-git -n <your webapp name> -g lineliffsample


Enter fullscreen mode Exit fullscreen mode

Use LIFF CLI with existing page

You can actually register any page as LIFF. In this section, I explan how to use CLI tool to register a page as LIFF.

1. Install liff (LIFF CLI tool).



npm install -g liff


Enter fullscreen mode Exit fullscreen mode

2. Run liff init to initialize the tool.



liff init <Channel Access Token>


Enter fullscreen mode Exit fullscreen mode

3. Register LIFF application. I use "tall" here but you can try "full" and "compact" as well.



liff add https://linecorp.com/en/ tall


Enter fullscreen mode Exit fullscreen mode

4. Get LIFF ID and Accessible URL.

5. Now, send the address by using "liff send" command or you can even send it via LINE to your friend. It works outside of the bot, too.



liff send <LIFF ID> <User ID>


Enter fullscreen mode Exit fullscreen mode

Develop LIFF application

In this section, I explain how to develop LIFF application with LIFF SDK.

Create a project

1. Create MyFirstLiff folder and open it via Visual Studio Code.



mkdir MyFirstLiff
cd MyFirstLiff
code .


Enter fullscreen mode Exit fullscreen mode

2. Create index.html.

image.png

3. Copy and paste following code to index.html.



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>
    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>

    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

4. Add liff.js in the same directory and paste the followig code.



window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        initializeApp(data);
    });
};

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}


Enter fullscreen mode Exit fullscreen mode

5. Save all.

Deploy LIFF Application.

1. Initialize git. Open the "Integrated terminal" and run git init.



git init


Enter fullscreen mode Exit fullscreen mode

2. Add remote which you obtain while creating WebApps above.



git remote add origin <remote git address of your WebApps> 


Enter fullscreen mode Exit fullscreen mode

3. Add all and commit.



git add .
git commit -m "initial"


Enter fullscreen mode Exit fullscreen mode

4. Push to deploy.



git push -u origin master


Enter fullscreen mode Exit fullscreen mode

5. Use LIFF CLI to register.



liff add <WebApps address> tall


Enter fullscreen mode Exit fullscreen mode

6. Now you can use the LIFF address to test. Make sure you get user ID and language of yourself.

Get user profile

1. Replace following code to index.html.



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>   
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>

    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

2. Replace code in liff.js.



window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}


Enter fullscreen mode Exit fullscreen mode

3. push the change.



git commit -am "add profile"
git push origin master


Enter fullscreen mode Exit fullscreen mode

4. As LIFF application address didn't change at all, simply reopen the page to confirm the behavior.

Send message from LIFF

You can send messages to LINE bot from LIFF application. This is great feature to integrate the page into bot.

See detail at liff.sendMessages()

1. Replcae the code for index.html



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>   
    <button id="sendmessagebutton">Send Message</button>
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>

    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

2. Replace code of liff.js



window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });

    // Send message
    document.getElementById('sendmessagebutton').addEventListener('click', function () {
        // https://developers.line.me/en/reference/liff/#liffsendmessages()
        liff.sendMessages([{
            type: 'text',
            text: "Send text message"
        }, {
            type: 'sticker',
            packageId: '2',
            stickerId: '144'
        }]).then(function () {
            window.alert("Sent");
        }).catch(function (error) {
            window.alert("Error sending message: " + error);
        });
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}


Enter fullscreen mode Exit fullscreen mode

3. Push again.



git commit -am "add send message"
git push origin master


Enter fullscreen mode Exit fullscreen mode

4. Use same LIFF address to confirm the behavior.

Open new window from LIFF

You can open URL inside LINE or outside of LINE from LIFF.

1. Replace code of index.html.



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>   
    <button id="openwindowbutton">Open the window in LINE</button>
    <button id="openwindowexternalbutton">Open the window outside of LINE</button>
    <button id="sendmessagebutton">Send Message</button>
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>

    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

2. Replace code of liff.js



window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });

    // Open window
    // https://developers.line.me/en/reference/liff/#liffopenwindow()
    document.getElementById('openwindowbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me'
        });
    });

    document.getElementById('openwindowexternalbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me',
            external: true
        });
    });

    // Send message
    document.getElementById('sendmessagebutton').addEventListener('click', function () {
        // https://developers.line.me/en/reference/liff/#liffsendmessages()
        liff.sendMessages([{
            type: 'text',
            text: "Send text message"
        }, {
            type: 'sticker',
            packageId: '2',
            stickerId: '144'
        }]).then(function () {
            window.alert("Sent");
        }).catch(function (error) {
            window.alert("Error sending message: " + error);
        });
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}


Enter fullscreen mode Exit fullscreen mode

3. Push again.



git commit -am "add openwindow"
git push origin master


Enter fullscreen mode Exit fullscreen mode

4. Use same LIFF URL to confirm the behavior.

Close LIFF application

User can close the LIFF by clicking [x] button or tap outside of LIFF area, but you can also close it by using SDK.

1. Replace code of index.html.



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>           
    <button id="closewindowbutton">Close LIFF application</button>
    <button id="openwindowbutton">Open the window in LINE</button>
    <button id="openwindowexternalbutton">Open the window outside of LINE</button>
    <button id="sendmessagebutton">Send Message</button>
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>

    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

2. Replace code of liff.js.



window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });

    // Close LIFF application
    // https://developers.line.me/en/reference/liff/#liffclosewindow()
    document.getElementById('closewindowbutton').addEventListener('click', function () {
        liff.closeWindow();
    });

    // Open window
    // https://developers.line.me/en/reference/liff/#liffopenwindow()
    document.getElementById('openwindowbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me'
        });
    });

    document.getElementById('openwindowexternalbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me',
            external: true
        });
    });

    // Send message
    document.getElementById('sendmessagebutton').addEventListener('click', function () {
        // https://developers.line.me/en/reference/liff/#liffsendmessages()
        liff.sendMessages([{
            type: 'text',
            text: "Send text message"
        }, {
            type: 'sticker',
            packageId: '2',
            stickerId: '144'
        }]).then(function () {
            window.alert("Sent");
        }).catch(function (error) {
            window.alert("Error sending message: " + error);
        });
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}


Enter fullscreen mode Exit fullscreen mode

3. Push.



git commit -am "add closewindow"
git push origin master


Enter fullscreen mode Exit fullscreen mode

4. Confirm the behavior.

Update or Delete LIFF application

You can update registered LIFF application by using LIFF CLI or you can delete them.

Update



liff update <liffId> <url> <type:full|tall|compact>


Enter fullscreen mode Exit fullscreen mode

Delete



liff delete <liffId>
liff deleteAll


Enter fullscreen mode Exit fullscreen mode

Enjoy LIFF!

Top comments (8)

Collapse
 
orz99 profile image
Lava • Edited

Hi Kenichiro thanks for the tutorial..
すみません、ちょっと闻いてもいいですか
How to Enable file upload outside of the Album folder in LiFF ?

HTML file upload like below, the opened file browser disable all files and can't be pickup

<input name="file" type="file" multiple />

Album is the only one can be pickup and upload.
Is any way to uplaod file other than images in LIFF?

It's ok when open LIFF in external browser. Is it the limitation of LINE itself?

Dsiable File browser
the only one could be pickup

Collapse
 
kenakamu profile image
Kenichiro Nakamura

That's an interesting question, which I don't have answer. If you run the LIFF app in external browser (as v2, you can run outside LINE) what happens?

Collapse
 
orz99 profile image
Lava

Thank you for your reply:)
Every thing is fine when running LIFF app in external browser.

Thread Thread
 
kenakamu profile image
Kenichiro Nakamura

In that case I believe it's LINE client limitation for now, unfortunately.

Thread Thread
 
orz99 profile image
Lava

Unable to understand the purpose of this restriction :(

When user install 3rd party file explorer such like "File Manager+", they can pickup any file form it on LIFF app -> upload -> switch to File Manager+

This restriction will only increase the user's inconvenience.

Thread Thread
 
kenakamu profile image
Kenichiro Nakamura

Yeah totally agree. Hope they find a way to solve it. iOS and Android may behave differently?

Collapse
 
lakshmi462 profile image
Lakshmi

Hi Kenichiro.. Thanks for the tutorial..
I was not able to download a pdf file inside liff browser but the same is working fine in liff browser. I am using jspdf to generate and download this pdf. Is there any way to download inside liff browser.
Thanks

Collapse
 
kenakamu profile image
Kenichiro Nakamura

The first thing you can do it to call the function only to see if Sdk has issue or you didn’t reach to the function.