You have an idea. You already had a responsive web app, it works well for mobile. It leads you to the thought of having a MVP mobile app to engage users: an app is built by embedded web-view. You also know React Native can help you build a cross-platform app. Very good solution: a React Native app with few WebView screens that point to correct links. Life is so easy, right? Unfortunately, it’s not.

Problems

You are right. It’s a great solution until you need to implement the authentication. There are at least 2 problems if your app requires user login.

Firstly, “remember me” doesn’t work although it works well on web. You need to enter credential whenever the app opens (in cold start).

Secondly, 3rd party authenticators like Google, Facebook… doesn’t work. You tap on “Login by Facebook”, Facebook login page is opened inside the app. Although you already logged in on Facebook app or OS browser, you need to enter Facebook credential whenever the app opens.

The reason is that WebView doesn’t share any data with OS browser. Each time the app starts, a “fresh” browser is initiated. It means there is no cookies, token, history… are stored by default.

There is only one weird function on your app while the rest are working perfectly. Yes, only one. But it kills your whole app. Do you know anyone who is willing to type username & password anytime he opens the app? Yes, if the app relates to very sensitive personal data like personal finance. But your app doesn’t.

Solutions

There are many solutions. I will describe the simplest one with less code change in your existing web app.

Facebook login

Let’s firstly solve the problem with 3rd party authenticators. I use Facebook as an example, you could treat others in the same way. The steps could be:

  • Handle event in WebView to detect user tapping on Facebook login button
  • Open client Facebook login, get the access token
  • Pass token to server to authenticate user

First step is setting up the Facebook SDK, please follow here: https://github.com/facebook/react-native-fbsdk

Second step is handling user tapping on Facebook login link on app, onNavigationStateChange of WebView is the good function to work on. Passing the token to server could be simply made by GET calling from WebView.

The code looks like:

There are some notes:

  • Line 20: we should let WebView stop loading to avoid strange UI: a popup of Facebook login on app on the top of Facebook web login screen (on app). It also stops WebView being redirected from https://facebook.com to https://m.facebook.com that lets the popup show twice.
  • Line 24: Facebook LoginManager caches the access token, calling logOut() before logInWithReadPermissions() helps app detects if user logout the app from other Facebook areas (web etc).
  • Line 64: you need to implement FacebookNativeLogin on server side then setting cookies etc.

Now it works? Yes, but not really. User is still required to press Facebook login when he opens the app. If you want “auto login”, componentDidMount could be a simple solution.

Remember me

Now it’s time for “remember me” function. The common solution is using the cookies. If you already had it running for web, your hands wouldn’t be much dirty. There is a simple solution with CookieManager, you could find it here: https://github.com/joeferraro/react-native-cookies

Well, let’s combine it with componentDidMount above:

Some notes:

  • Line 3: replace it with your correct cookies
  • Line 5: I introduce loggedIn state because Facebook login is separated with your system username/password login. It lets you update uri in WebView of render() function above with a condition combined by loggedIn and facebookToken. But it’s not difficult, right? Hmm, loggedIn isn’t a good name.

Done? Almost. You could see it works really well on Android but not on iOS. In cold start, CookieManager.get() returns value on Android but doesn’t on iOS. Then storing and restoring cookies programmatically is a solution. AsyncStorage could help https://facebook.github.io/react-native/docs/asyncstorage.html. Just add the few lines of code to onNavigationStateChange to store the cookie and set it back on componentDidMount. Fortunately, CookieManager.set() only works on iOS.

Know issues

I hope it help you overcome the common issue of web-view app. I don’t want to put the setting cookies into existing functions because they are too long now. You should refactor it after getting it run.

Is the solution simple? Yes. Is it perfect? No. There are some small issues:

  • We call GET to FacebookNativeLogin with accessToken. Might POST be a bit better?
  • What if the cookies is expired? Is it good to still keep user login? A solution is storing username/password by AsyncStorage and injecting Javascript to auto fill username/password text fields. But I don’t prefer storing any data like that.

But if you are interested in those topics, I will go into the example next post.

377 total views, 4 views today

Bài viết đăng trên Tạp Chí Lập Trình

Array có mặt trong hầu hết các ngôn ngữ lập trình, là một cấu trúc dữ liệu cho phép lưu trữ và truy xuất các phần tử ngẫu nhiên dựa trên vị trí. Trong Javascript, Array có gì khác?

Một lớp

Và do đó, chúng ta có thể tạo một đối tượng Array để lưu trữ các phần tử. Có 2 cách thường dùng để khởi tạo 1 đối tượng Array:

hoặc:

sẽ khởi tạo 1 đối tượng mảng arr chứa các phần tử “Bob”, “Jobs” và “Bill”.

No-type

Như bạn đã biết, trong Javascript, nói chung các biến không cần chỉ định rõ kiểu. Do đó, chúng ta có thể chứa những phần tử có kiểu khác nhau trong cùng 1 mảng như:

Điều này rất khác so với những ngôn ngữ như C++, Java… khi khai báo mảng với int arr[10]; sẽ giới hạn mảng arr chỉ chứa các số kiểu int.

Mutable

Điều gì xảy ra nếu chúng ta thực hiện đoạn mã sau?

Sẽ chẳng có lỗi OutOfRange nào như chúng ta mong đợi. Đơn giản vì Javascript tự điều chỉnh kích thước của mảng cho phù hợp, hay khả năng “co giãn”, còn gọi là mutable. Có lẽ Array mang hình ảnh của List?

Và..

Ngoài việc lưu trữ những phần tử có kiểu khác nhau, đối tượng Array còn cho phép dùng nhiều kiểu dữ liệu khác nhau làm “key”.

Hãy thử đoạn mã sau:

Đến đây chắc bạn cũng nhận ra, đối tượng Array không giống như mảng thông thường, chỉ cho phép truy xuất qua chỉ số là số nguyên, mà còn cho phép truy xuất qua chỉ số là một đối tượng bất kỳ. Thực ra, Javascript lưu trữ các đối tượng dưới dạng key-value-based, tức là mỗi đối tượng key (khoá) sẽ tương ứng (ánh xạ) với một đối tượng value (giá trị) theo cặp. Cấu trúc dữ liệu nào lưu trữ dưới dạng key-value-based? Có lẽ là Map.

Ngoài ra..

Hãy để ý các phương thức có sẵn của đối tượng Array, có lẽ bạn sẽ ấn tượng với 2 phương thức hay được sử dụng nhất: pop() và push().

Cấu trúc dữ liệu nào sở hữu những phương thức này? Stack và Queue. Vậy đối tuợng Array mang hình ảnh của Stack hay Queue? Cách kiểm chứng đơn giản nhất là dựa trên cơ chế của 2 kiểu cấu trúc dữ liệu này: Stack hoạt động theo phương thức LIFO (Last In First Out – Vào sau ra trước), Queue thì ngược lại LILO (Last In Last Out – Vào sau ra sau) (Có người thích gọi cơ chế hoạt động của Stack là: FILO và Queue là: FIFO). Hãy đưa một phần tử vào một Array đã có dữ liệu qua phương thức push(), tiếp đó, lấy phần tử trong Array qua phương thức pop(). Nếu hai phần tử này giống nhau, chắc chắn Array hoạt động theo phương thức LIFO tức là Stack, ngược lại Array hoạt động theo phương thức LILO hay Queue.

OK, hãy thử đoạn mã sau:

Chắc bạn đã có câu trả lời.

Tiếp theo…

Làm sao có thể biến cấu trúc dữ liệu của đối tượng Array từ Stack sang Queue và ngược lại? Hãy thử sức.

Gợi ý: Sử dụng phương thức reverse() cho phép đảo ngược các phần tử trong đối tượng Array hoặc phương thức shift() cho phép lấy ra khỏi mảng phần tử đứng đầu.

Lời kết

Giờ đây chắc bạn đã thấy sức mạnh của đối tượng Array trong Javascript, nó có thể biến đổi uyển chuyển giữa những cấu trúc dữ liệu phức tạp khác nhau như List, Map, Stack hay Queue.

Một thông tin đáng mừng là Javascript chỉ là một đại diện cho một lớp những scripting language (ngôn ngữ kịch bản, như PHP, Python…), trong đó đối tượng Array được sử dụng như cấu trúc dữ liệu chính và thể hiện rất nhiều hình ảnh khác nhau như trong Javascript.

Hãy tiếp tục tìm hiểu xem Array có thể mô tả cấu trúc dữ liệu nào khác và cùng update vào bài viết.

508 total views, 1 views today