Introduction

SAST-EVENTO-MOBILE is a cross-platform mobile application for our association: Student Association of Science and Technology (SAST). It is a events management and distribution application, based on Ionic/React and Capacitor.

At a very previous stage, I have to make a choice between Hybrid and Mini-Program. It was a very hard decision. I finally chose Hybrid because of the following reasons:

  1. On Mini-Program, we have to face a very strict censor of the carriers platform like WeChat. Not only for the content, but also for the data and permissions we ask for, for example, the student ID and the notifications.
  2. In China, the Mini-Program also acquires a ICP license to run like a website and a real application. For more information, please visit 工业和信息化部关于开展移动互联网应用程序备案工作的通知.
  3. The Mini-Program is not a real application, and it has different standards from different carriers. Although some cross-platform Mini-Program frameworks, like uni-app, are very mature, they still have many terrible bugs and most of them are unavoidable. Besides, most carriers have a strict limit on the Mini-Programs, like the package size, the resources from the Internet, etc.

Then, I need to choose a framework for the Hybrid application. I have considered React Native, Flutter and Ionic. Each of them are excellent and powerful, but I finally chose Ionic because of the following reasons:

  1. Except mobile apps, I also need a PWA for iOS users, since our association had not gotten the Apple Developer Account yet. As a result, React Native is not a good choice.
  2. Flutter is a very good choice, but our association and I have no experience on Dart. Besides, the Flutter is not very friendly to the web.
  3. The Capacitor is powerful support for Ionic. It can help us to build a PWA and a Hybrid app easily. After our association gets the Apple Developer Account, we can also build a native iOS app with the same codebase.

Finally, I chose React as the framework for the Ionic app. But I used Vue previously and had no experience on React. The reason is that most projects in our association are based on React, and I am going to learn it.

Developing

Since I have not used React before, I needed to learn it first. I followed the documents on its official website, try to find the differences between Vue and itself, and learn its basic usage. After I finished the basics, I started to have a glance at other React projects in our association's repository and learn from them. At the point where I felt I had enough knowledge to start developing the project, I created a repository and walked on the road of developing.

Besides, most APIs had been finished before I started to develop the mobile app, and tested by other projects. So I just needed to use them and design the UI.

Basic Functions

SAST-EVENTO is information distribution and management platform for our association and its members, and the most important function of its mobile app is information display and notification.

Home Page

Therefore, according to our events information, I designed the event display card and the home page. The home page is a list of events, and each event is displayed as a card. The card contains the event's title, time, description, and other basic information of the event.

In the home page, I showed some slide images, conducting events and all events. They corresponded to three different APIs. Among them, the API of all events was a pagination API, so I used ion-infinite-scroll to contain it, which perfectly fit the need of the APP and the parameters of the API.

all events

When I scroll down and reach the bottom, the app will send a request to the API to get the next page of events. After the request is completed, the app will add the new events to the list and show them to the user.

Event Page

The user can also click on the event card to enter the event detail page. In the event detail page, the app will show all information of the event, like the start time and end time.

event detail

In the detail page, user can also click on the button to register the event, subscribe the event or share the event. The subscribe button will register a local notifications with @capacitor/local-notifications, and the share button uses @capacitor/share to call system share API.

share API

Department Page

To help the user to find the events they are interested in, I designed the department page, which is display.

departments

In the department page, the user can see all departments of our association, and click on the department card to enter the department detail page. In the department detail page, the user can see all events of the department.

department detail

User System

Our User System is very simple and basic, including login, register, logout, user-profile and those events that the user has attended. More features will be added as the back-end is updated.

In this year, the OAuth 2.0 system of our association - SAST-Link - is on private test, and it became the prior authentication method for SAST-EVENTO.

SAST-Link

To use the service, I need to register a OAuth 2.0 client with a redirect URI on the SAST-Link server, and then I can get the client ID and client secret. Then I register a client with those information on the SAST-EVENTO back-end. With the client ID and redirect URI, the mobile app uses SAST-Link OAuth 2.0 to authenticate the user.

sequenceDiagram title OAuth2 Steps Client->>SAST-Link: request for authorization SAST-Link->>Client: redirect to oauth page with code Client->>Server: request for access token with code Server->>SAST-Link: request for access token with code SAST-Link->>Server: response with access token Server->>SAST-Link: request for user info with access token SAST-Link->>Server: response with user info Server->>Client: response with user info and token

If a new user try to login with SAST-Link, its action will be recognized as register. Besides, the user can also login with the username and password. The password will be encrypted with MD5 before sending to the server.

login methods

After login, the user can see its profile, edit it, look up the events it has attended, and so on.

In China, QR Code login is very very popular for some unknown reasons, we also considered about this kind of login method, but it still has many problems to resolve, especially in the back-end.

Schedule System

To help the users manage their events, we have a schedule system. The users can register and participate in events, and the events will be added to their schedule automatically. Besides, those departments that the user has subscribed will also be added to the schedule page. In this page, we hope the user can easily find the events they are interested in or they plan to join in.

register page participate page

We plan to add notification at the system level. When the event is about to start, the user will receive a notification from the system.

Problems

Of course, I met many problems during the development, and some of them are really give me a headache. I will pick some of them and share with you.

QR Code Scanning

In our design, a short code is generated by the back-end, and our members can scan the QR code, which is rendered on the front-end or the desktop platform, to check in a event. When the user scans the QR code, the app will send a request to the back-end to check in the event.

Firstly, I used @capacitor-community/barcode-scanner to scan the QR code, but it did not work well. In my tests, the scanner can recognize the QR code well, but only on Windows with the chrome, it can display the preview. That means most mobile users could not make sure that the QR code is captured by their devices. Since it was the first time I tried the Hybrid Dev, I could not recognize where was the bug. I followed the guides and rechecked them again and again: I added uses-permission in the AndroidManifest.xml and made all Ionic page transparent, but it still did not work. In the end, I gave up the capacitor plugin and used another QR code scanner - react-zxing, which is based on zxing-js. Obviously this will bring some performance loss, but it brought some easier APIs and usable scanner, and I thought this exchange was acceptable.

Now, the QR code scanning tool currently requires further optimization. For instance, when the QR code occupies a large portion of the screen, it leads to difficulty in recognizing the QR code. In the upcoming development phase, we will attempt to optimize this by restricting the range of the incoming video stream for recognition purposes.

APP Launched by Browser

This problem was found after the release of the first Android APP. In the mentioned article, I highlighted our use of OAuth 2.0 as the login method. However, in the OAuth login process, the frontend webpage of OAuth redirects to the originally specified Redirect URL. In the previous versions, we only used PWA, which was deeply linked with the URL. But once we used the Android APP, which was running on localhost, there would be problems with the redirect step.

  1. The OAuth page is running on browser so we need to enhance the OAuth page in my APP, and make it possible to launch our APP and correctly send the code.
  2. I need to parse the URL used to launch this app during startup to enable internal app navigation.

Since I seldom used an Android device, I wasn't familiar with various Android protocols like Deep Links. I encountered significant obstacles while addressing the two issues mentioned above, before I found Configuring Android. In the very beginning stage, I even try to use Java to solve the problems.

For the first issue, I added the following code in AndroidManifest.xml:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <data android:pathPrefix="/oauth" android:scheme="@string/custom_url_scheme" />
</intent-filter>
<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <data android:scheme="https" />
    <data android:host="evento.sast.fun" />
</intent-filter>

In this way, I can launch my APP with a URL like evento://home or evento://evento.sast.fun. However, this is not enough. I need to parse the URL and send the code to the server. I found the solution in Capacitor DOCS

When the native app is opened after a deep link is clicked, the mobile OS doesn't automatically know where to route the user. This must be implemented within the app itself using the Capacitor App API on app startup.

I installed @capacitor/app and add a listener in AppUrlListener.ts:

import { App, URLOpenListenerEvent } from "@capacitor/app";
import React, { useEffect } from "react";

const AppUrlListener: React.FC<any> = () => {
  useEffect(() => {
    App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {
      console.log("Url: " + event.url);
      const slug = event.url.split('.fun').pop();
      if (slug) {
        location.href = slug;
      }
    });
  }, []);

  return null;
};

export default AppUrlListener;

In this way, I can get the URL and parse it to get the code and send it to the server.

Future

The fundamental features of this app have been completed. In the future, I plan to add enhancements to improve user experience, such as implementing a global fuzzy search to help users easily find past events. Additionally, I'll gradually enhance the development documentation to facilitate subsequent developers in quickly taking over the project.

At Last

This project might not hold many surprises; it's just a simple app. However, to me, it marks my first mobile application. Throughout this journey, besides mastering the React framework, I gained valuable insights into native development, which I find immensely valuable. At the same time, this marks the first fully-fledged mobile app for our association in the past few years. This shift slightly alters the dominance previously held by mini-programs, initiating a change in the landscape.

I've thoroughly enjoyed the development experience on this project. Though it still has its shortcomings, I'm committed to refining it as much as possible.

Be a Neutral Listener, Dialectical Thinker, and Practitioner of Knowledge