LIFF initialization can fail if a user clicks "Cancel" on the "Grant permission" screen, or if an error occurs in the process of liff.init().
136 |
137 |
138 |
139 |
Unable to receive the LIFF ID as an environment variable.
140 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/public/liff-starter.js:
--------------------------------------------------------------------------------
1 | window.onload = function() {
2 | const useNodeJS = true; // if you are not using a node server, set this value to false
3 | const defaultLiffId = ""; // change the default LIFF value if you are not using a node server
4 |
5 | // DO NOT CHANGE THIS
6 | let myLiffId = "";
7 |
8 | // if node is used, fetch the environment variable and pass it to the LIFF method
9 | // otherwise, pass defaultLiffId
10 | if (useNodeJS) {
11 | fetch('/send-id')
12 | .then(function(reqResponse) {
13 | return reqResponse.json();
14 | })
15 | .then(function(jsonResponse) {
16 | myLiffId = jsonResponse.id;
17 | initializeLiffOrDie(myLiffId);
18 | })
19 | .catch(function(error) {
20 | document.getElementById("liffAppContent").classList.add('hidden');
21 | document.getElementById("nodeLiffIdErrorMessage").classList.remove('hidden');
22 | });
23 | } else {
24 | myLiffId = defaultLiffId;
25 | initializeLiffOrDie(myLiffId);
26 | }
27 | };
28 |
29 | /**
30 | * Check if myLiffId is null. If null do not initiate liff.
31 | * @param {string} myLiffId The LIFF ID of the selected element
32 | */
33 | function initializeLiffOrDie(myLiffId) {
34 | if (!myLiffId) {
35 | document.getElementById("liffAppContent").classList.add('hidden');
36 | document.getElementById("liffIdErrorMessage").classList.remove('hidden');
37 | } else {
38 | initializeLiff(myLiffId);
39 | }
40 | }
41 |
42 | /**
43 | * Initialize LIFF
44 | * @param {string} myLiffId The LIFF ID of the selected element
45 | */
46 | function initializeLiff(myLiffId) {
47 | liff
48 | .init({
49 | liffId: myLiffId
50 | })
51 | .then(() => {
52 | // start to use LIFF's api
53 | initializeApp();
54 | })
55 | .catch((err) => {
56 | document.getElementById("liffAppContent").classList.add('hidden');
57 | document.getElementById("liffInitErrorMessage").classList.remove('hidden');
58 | });
59 | }
60 |
61 | /**
62 | * Initialize the app by calling functions handling individual app components
63 | */
64 | function initializeApp() {
65 | displayLiffData();
66 | displayIsInClientInfo();
67 | registerButtonHandlers();
68 |
69 | // check if the user is logged in/out, and disable inappropriate button
70 | if (liff.isLoggedIn()) {
71 | document.getElementById('liffLoginButton').disabled = true;
72 | } else {
73 | document.getElementById('liffLogoutButton').disabled = true;
74 | }
75 | }
76 |
77 | /**
78 | * Display data generated by invoking LIFF methods
79 | */
80 | function displayLiffData() {
81 | document.getElementById('browserLanguage').textContent = liff.getLanguage();
82 | document.getElementById('sdkVersion').textContent = liff.getVersion();
83 | document.getElementById('lineVersion').textContent = liff.getLineVersion();
84 | document.getElementById('isInClient').textContent = liff.isInClient();
85 | document.getElementById('isLoggedIn').textContent = liff.isLoggedIn();
86 | document.getElementById('deviceOS').textContent = liff.getOS();
87 | }
88 |
89 | /**
90 | * Toggle the login/logout buttons based on the isInClient status, and display a message accordingly
91 | */
92 | function displayIsInClientInfo() {
93 | if (liff.isInClient()) {
94 | document.getElementById('liffLoginButton').classList.toggle('hidden');
95 | document.getElementById('liffLogoutButton').classList.toggle('hidden');
96 | document.getElementById('isInClientMessage').textContent = 'You are opening the app in the in-app browser of LINE.';
97 | } else {
98 | document.getElementById('isInClientMessage').textContent = 'You are opening the app in an external browser.';
99 | document.getElementById('shareTargetPicker').classList.toggle('hidden');
100 | }
101 | }
102 |
103 | /**
104 | * Register event handlers for the buttons displayed in the app
105 | */
106 | function registerButtonHandlers() {
107 | // openWindow call
108 | document.getElementById('openWindowButton').addEventListener('click', function() {
109 | liff.openWindow({
110 | url: 'https://line.me',
111 | external: true
112 | });
113 | });
114 |
115 | // closeWindow call
116 | document.getElementById('closeWindowButton').addEventListener('click', function() {
117 | if (!liff.isInClient()) {
118 | sendAlertIfNotInClient();
119 | } else {
120 | liff.closeWindow();
121 | }
122 | });
123 |
124 | // sendMessages call
125 | document.getElementById('sendMessageButton').addEventListener('click', function() {
126 | if (!liff.isInClient()) {
127 | sendAlertIfNotInClient();
128 | } else {
129 | liff.sendMessages([{
130 | 'type': 'text',
131 | 'text': "You've successfully sent a message! Hooray!"
132 | }]).then(function() {
133 | window.alert('Message sent');
134 | }).catch(function(error) {
135 | window.alert('Error sending message: ' + error);
136 | });
137 | }
138 | });
139 |
140 | // scanCode call
141 | document.getElementById('scanQrCodeButton').addEventListener('click', function() {
142 | if (!liff.isInClient()) {
143 | sendAlertIfNotInClient();
144 | } else {
145 | liff.scanCode().then(result => {
146 | // e.g. result = { value: "Hello LIFF app!" }
147 | const stringifiedResult = JSON.stringify(result);
148 | document.getElementById('scanQrField').textContent = stringifiedResult;
149 | toggleQrCodeReader();
150 | }).catch(err => {
151 | document.getElementById('scanQrField').textContent = "scanCode failed!";
152 | });
153 | }
154 | });
155 |
156 | // get access token
157 | document.getElementById('getAccessToken').addEventListener('click', function() {
158 | if (!liff.isLoggedIn() && !liff.isInClient()) {
159 | alert('To get an access token, you need to be logged in. Please tap the "login" button below and try again.');
160 | } else {
161 | const accessToken = liff.getAccessToken();
162 | document.getElementById('accessTokenField').textContent = accessToken;
163 | toggleAccessToken();
164 | }
165 | });
166 |
167 | // get profile call
168 | document.getElementById('getProfileButton').addEventListener('click', function() {
169 | liff.getProfile().then(function(profile) {
170 | document.getElementById('userIdProfileField').textContent = profile.userId;
171 | document.getElementById('displayNameField').textContent = profile.displayName;
172 |
173 | const profilePictureDiv = document.getElementById('profilePictureDiv');
174 | if (profilePictureDiv.firstElementChild) {
175 | profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
176 | }
177 | const img = document.createElement('img');
178 | img.src = profile.pictureUrl;
179 | img.alt = 'Profile Picture';
180 | profilePictureDiv.appendChild(img);
181 |
182 | document.getElementById('statusMessageField').textContent = profile.statusMessage;
183 | toggleProfileData();
184 | }).catch(function(error) {
185 | window.alert('Error getting profile: ' + error);
186 | });
187 | });
188 |
189 | document.getElementById('shareTargetPicker').addEventListener('click', function () {
190 | if (liff.isApiAvailable('shareTargetPicker')) {
191 | liff.shareTargetPicker([{
192 | 'type': 'text',
193 | 'text': 'Hello, World!'
194 | }]).then(
195 | document.getElementById('shareTargetPickerMessage').textContent = "Share target picker was launched."
196 | ).catch(function (res) {
197 | document.getElementById('shareTargetPickerMessage').textContent = "Failed to launch share target picker.";
198 | });
199 | }
200 | });
201 |
202 | // login call, only when external browser is used
203 | document.getElementById('liffLoginButton').addEventListener('click', function() {
204 | if (!liff.isLoggedIn()) {
205 | // set `redirectUri` to redirect the user to a URL other than the front page of your LIFF app.
206 | liff.login();
207 | }
208 | });
209 |
210 | // logout call only when external browse
211 | document.getElementById('liffLogoutButton').addEventListener('click', function() {
212 | if (liff.isLoggedIn()) {
213 | liff.logout();
214 | window.location.reload();
215 | }
216 | });
217 | }
218 |
219 | /**
220 | * Alert the user if LIFF is opened in an external browser and unavailable buttons are tapped
221 | */
222 | function sendAlertIfNotInClient() {
223 | alert('This button is unavailable as LIFF is currently being opened in an external browser.');
224 | }
225 |
226 | /**
227 | * Toggle access token data field
228 | */
229 | function toggleAccessToken() {
230 | toggleElement('accessTokenData');
231 | }
232 |
233 | /**
234 | * Toggle profile info field
235 | */
236 | function toggleProfileData() {
237 | toggleElement('profileInfo');
238 | }
239 |
240 | /**
241 | * Toggle scanCode result field
242 | */
243 | function toggleQrCodeReader() {
244 | toggleElement('scanQr');
245 | }
246 |
247 | /**
248 | * Toggle specified element
249 | * @param {string} elementId The ID of the selected element
250 | */
251 | function toggleElement(elementId) {
252 | const elem = document.getElementById(elementId);
253 | if (elem.offsetWidth > 0 && elem.offsetHeight > 0) {
254 | elem.style.display = 'none';
255 | } else {
256 | elem.style.display = 'block';
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LIFF v2 starter app
2 |
3 | This is a small web application that demonstrates the basic functionality of the [LINE Front-end Framework (LIFF)](https://developers.line.biz/en/docs/liff/overview/).
4 |
5 | ## Deploy methods
6 |
7 | Depending on how you want to use LIFF, choose one of these methods for deploying the LIFF v2 starter app:
8 |
9 | - If you merely want to try the functions LIFF offers, see [Use Heroku button to deploy the app without using the terminal](#Use-Heroku-button-to-deploy-the-app-without-using-the-terminal)
10 | - If you want to develop a LIFF app using Heroku and Node.js, see [Customize the app and deploy it on Heroku via the terminal](#Customize-the-app-and-deploy-it-on-Heroku-via-the-terminal)
11 | - If you want to develop a LIFF app using a server platform of your choice, see [Use any other server platform](#deploy-the-app-using-any-other-server-platform)
12 |
13 | ## Use Heroku button to deploy the app without using the terminal
14 |
15 | Follow the below instructions to deploy your app using the Heroku button and Node.js without customization.
16 |
17 | ### What you'll need
18 |
19 | | Item | Description |
20 | | ---- | ----------- |
21 | | LINE Messaging API channel | A channel forms the connection between your app and the LINE Platform. Create a channel on the [LINE Developers console](https://developers.line.biz/console/register/messaging-api/channel/). |
22 | | Heroku account (optional) | [Heroku](https://www.heroku.com) is a cloud service that lets you deploy and serve web apps for free. You don't need a Heroku account if you're [deploying the app on another platform](#deploy-the-app-using-any-other-server-platform). |
23 |
24 | ### Deploy the app using 'Deploy to Heroku' button
25 |
26 | [](https://heroku.com/deploy?template=https://github.com/line/line-liff-v2-starter)
27 |
28 | 1. Click **Deploy to Heroku** above.
29 | 2. On the "Create New App" page in Heroku, fill in the required information.
30 | 3. Click **Deploy app**.
31 | 4. Click **View** to confirm that your app is successfully deployed. You should see a page with the text "You have not assigned any value for LIFF ID".
32 | 5. Take a note of your app's URL (`https://{Heroku app name}.herokuapp.com`). You'll need it when you add the app to LIFF.
33 |
34 | ### Add the starter app to LIFF
35 |
36 | 1. Follow the instructions on the page [Adding a LIFF app](https://developers.line.biz/en/docs/liff/registering-liff-apps/).
37 | 2. Take a note of your LIFF ID, because you'll need it for the next part. The LIFF ID is the final part of the **LIFF URL** shown in the console: `https://liff.line.me/{liffId}`.
38 | 3. Locate the **Scope** option and click the **Edit** button.
39 | 4. Click the **View all** option and enable `chat_message.write`. This scope is required for the LIFF app to send messages on behalf of the user.
40 | 5. Change the status of LIFF app to **Published**.
41 |
42 | ### Pass your LIFF ID to the app using an environment variable
43 |
44 | 1. In Heroku, go to [Dashboard](https://dashboard.heroku.com/).
45 | 2. Select your app.
46 | 3. On the **Settings** tab, click **Reveal Config Vars**.
47 | 4. Enter a new key called `MY_LIFF_ID` with your LIFF ID as the value.
48 | 5. Click **Add** to save.
49 | 6. Browse back to your app's URL (`https://{Heroku app name}.herokuapp.com`) and confirm that your app is operational. You should see a number of buttons, such as **Open External Window** and **Close LIFF App**.
50 |
51 | For more information about how to try the app, see [Trying the app](#trying-the-app).
52 |
53 | ### Checking logs
54 |
55 | To get more information, you can check your app's logs using Heroku's GUI or [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli).
56 |
57 | #### Check your app's logs using Heroku's GUI
58 |
59 | To get more information, check your app's logs online:
60 |
61 | 1. In Heroku, go to [Dashboard](https://dashboard.heroku.com/).
62 | 2. Select the app you just created.
63 | 3. In the top-right corner, click **More**.
64 | 4. Click **View logs**.
65 |
66 | You'll find the log under **Application Logs**.
67 |
68 | #### Check your app's logs using Heroku CLI
69 |
70 | 1. Log in to Heroku from the command line (if you haven't already).
71 |
72 | ```shell
73 | $ heroku login
74 | ```
75 |
76 | 2. Check the logs.
77 |
78 | ```shell
79 | $ heroku logs --app {Heroku app name} --tail
80 | ```
81 |
82 |
83 | ## Customize the app and deploy it on Heroku via the terminal
84 |
85 | Follow the below instructions to deploy your customized app using Heroku and Node.js.
86 |
87 | ### Install the app on your local machine
88 |
89 | 1. Make sure you have the following installed.
90 |
91 | - [Git](https://git-scm.com/)
92 | - [Node.js](https://nodejs.org/en/)
93 | - Items listed [here](#what-youll-need)
94 |
95 | 2. Clone the [line-liff-starter](https://github.com/line/line-liff-v2-starter) GitHub repository.
96 |
97 | ```shell
98 | git clone https://github.com/line/line-liff-v2-starter
99 | ```
100 | 3. `cd` into `line-liff-v2-starter` directory.
101 |
102 | 4. Install the dependencies by running:
103 | ```shell
104 | $ npm install
105 | ```
106 |
107 | ### Link your local repository to Heroku
108 |
109 | 1. Log in to Heroku from the command line.
110 |
111 | ```shell
112 | $ heroku login
113 | ```
114 |
115 | 2. Create a named Heroku app.
116 |
117 | ```shell
118 | $ heroku create {Heroku app name}
119 | ```
120 |
121 | 3. Take a note of your app's URL (`https://{Heroku app name}.herokuapp.com`). You'll need it when you add the app to LIFF.
122 |
123 | 4. Add a remote for Heroku to your local repository.
124 |
125 | ```shell
126 | $ heroku git:remote -a {Heroku app name}
127 | ```
128 |
129 | ### Add the starter app to LIFF
130 |
131 | 1. Follow the instructions on the page [Adding a LIFF app](https://developers.line.biz/en/docs/liff/registering-liff-apps/).
132 | 2. Take a note of your LIFF ID, because you'll need it for the next part. The LIFF ID is the final part of the LIFF URL shown in the console: `line://app/{liffId}`
133 |
134 | ### Customize and deploy the app via terminal
135 |
136 | 1. Set your LIFF ID using an environment variable.
137 |
138 | ```shell
139 | heroku config:set MY_LIFF_ID={liffId}
140 | ```
141 |
142 | 2. Copy your environment variable into the `.env` file for local testing.
143 |
144 | Heroku recommends setting up an `.env` file to use an environment variable in a local environment.
145 | ```shell
146 | $ heroku config:get MY_LIFF_ID -s >> .env
147 | ```
148 | Note: Don't commit the `.env` file to GitHub. To exclude it, add the `.env` file to your `.gitignore`.
149 |
150 | 3. Customize your app. For more information about available LIFF methods, see [API reference](https://developers.line.biz/en/reference/liff/).
151 |
152 | 4. Run the app locally to preview your changes:
153 |
154 | ```shell
155 | heroku local
156 | ```
157 | View the app by browsing to [localhost:5000](http://localhost:5000/).
158 |
159 | 5. If you're happy with your changes, stage, commit, and deploy the app.
160 |
161 | ```shell
162 | $ git add .
163 | $ git commit -m "My first commit"
164 | $ git push heroku master
165 | ```
166 |
167 | 6. Browse to your app's URL (`https://{Heroku app name}.herokuapp.com`) and confirm that your app is operational. You should see a number of buttons, such as **Open External Window** and **Close LIFF App**.
168 |
169 | 7. Lastly, check whether your channel status is **Published**.
170 |
171 | For more information about how to try the app, see [Trying the app](#trying-the-app).
172 |
173 | ### Checking logs
174 |
175 | To get more information, check your app's logs using Heroku's GUI or [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli).
176 | Refer to [this section](#checking-logs) for more information.
177 |
178 | ## Deploy the app using any other server platform
179 |
180 | Follow the below instructions to deploy your app using the server platform of your choice.
181 |
182 | ### Prerequisites
183 | | Item | Description |
184 | | ---- | ----------- |
185 | | LINE Messaging API channel | A channel forms the connection between your app and the LINE Platform. Create a channel on the [LINE Developers console](https://developers.line.biz/console/register/messaging-api/channel/). |
186 |
187 |
188 | ### Clone the repository
189 |
190 | 1. Clone the [line-liff-starter](https://github.com/line/line-liff-v2-starter) repository.
191 |
192 | ```shell
193 | git clone https://github.com/line/line-liff-v2-starter
194 | ```
195 |
196 | 2. `cd` into `line-liff-v2-starter` directory.
197 |
198 | ### Prepare your app and server
199 |
200 | 1. Set the `useNodeJS` variable to `false` in `public/liff-starter.js`.
201 |
202 | ```shell
203 | const useNodeJS = false;
204 | ```
205 | 2. Remove Heroku and Node.js specific files (`app.json` , `index.js`, `package.json`, and `Procfile`) from your workspace.
206 | 3. Host the files on a web server.
207 |
208 | ### Add the starter app to LIFF
209 |
210 | 1. Follow the instructions on the page [Adding a LIFF app](https://developers.line.biz/en/docs/liff/registering-liff-apps/).
211 | 2. Take a note of your LIFF ID, because you'll need it for the next part. The LIFF ID is the final part of the LIFF URL shown in the console: `line://app/{liffId}`
212 |
213 | 3. Set your LIFF ID to the `defaultLiffId` variable in `public/liff-starter.js`.
214 | ```shell
215 | const defaultLiffId = "{liffId}";
216 | ```
217 |
218 | ## Trying the app
219 |
220 | ### Try the app in LINE
221 |
222 | You can open your LIFF app in LINE by creating a simple link from any chat:
223 |
224 | 1. In any LINE chat, type `line://app/{liffId}` and send the message. (For example, if your LIFF ID is `123`, send the message `line://app/123`.)
225 | 2. Tap the link in your own message.
226 | 3. Agree to grant the required permissions to the LIFF app.
227 |
228 | ### Try the app in your browser
229 |
230 | To open your LIFF app in your browser, enter the app's Heroku URL: `https://{Heroku app name}.herokuapp.com`
231 |
232 | ## App features
233 |
234 | You'll find the following buttons in the starter app.
235 |
236 | ℹ️ Some buttons are available only in either LINE's in-app browser or in a regular browser. See also the [API reference](https://developers.line.biz/en/reference/liff/).
237 |
238 | | Button | Description | LINE browser | Regular browser |
239 | | ------ | ----------- | :------------: | :---------------: |
240 | | Open External Window | Opens `https://line.me` in LINE's in-app browser. | ✅ | ✅ |
241 | | Close LIFF App | Closes the LIFF app. | ✅ | ❌ |
242 | | Open QR Code Reader | Opens the QR code reader and outputs the result. ⚠️ **Due to a technical issue, `liff.scanCode()` is temporarily unavailable on LINE for iOS v9.19.0 and later.**| ✅ | ❌ |
243 | | Send Message | Sends a sample message on behalf of the user if the LIFF app is opened in the chat screen. | ✅ | ❌ |
244 | | Get Access Token | Gets the current user's access token. | ✅ | ✅ |
245 | | Get Profile | Gets the current user's profile. | ✅ | ✅ |
246 | | Open Share Target Picker | Displays the target picker (screen for selecting a group or friend) and sends a sample message to the selected target. | ✅ | ❌ |
247 | | Log In | Performs LINE Login for web apps. Once the user is authenticated and authorized, the LIFF app will be able to obtain information such as access token and user profile. | ❌ | ✅ |
248 | | Log Out | Logs out the user. | ✅ | ✅ |
249 |
250 | For API calls associated with the buttons, see [Calling the LIFF API](https://developers.line.biz/en/docs/liff/developing-liff-apps#calling-liff-api).
251 |
252 | [heroku-cli]: https://devcenter.heroku.com/articles/heroku-cli
253 | [liff-api-ref]: https://developers.line.biz/en/reference/liff/
254 | [calling-liff-api]: https://developers.line.biz/en/docs/liff/developing-liff-apps#calling-liff-api
255 |
--------------------------------------------------------------------------------