Develop a Syncable Android Widget Using Ionic Framework and Capacitor
Introduction
In this post, we’ll walk through the process of creating a simple yet powerful counter app using Ionic and Capacitor. The focus of this tutorial is to show how we can synchronize the counter value between Ionic app and an Android home screen widget. We’ll explore setting up a custom JavaScript interface in the Android native code to allow the Ionic app to interact directly with the widget.
Why this is important :
When we're building a mobile app using Ionic, we're essentially creating a web-based app that runs inside a WebView ,a kind of browser window embedded in our app. But what if we need to do something that’s not possible with just web technologies, like updating an Android widget? push notification ?. This is where connecting Ionic app to Android's native capabilities comes in.
Prerequisites
Before we begin, ensure you have the following:
- Ionic CLI installed.
- A basic understanding of Ionic and Angular.
- Familiarity with Java development for Android.
- Android Studio set up for building and testing the native code.
Step 1: Set Up the Ionic Counter App
1. Create a new Ionic project:
ionic start counterApp blank --type=angular
cd counterApp
2. Create the Counter UI:
// Home.page.html
<ion-header>
<ion-toolbar>
<ion-title>Counter</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<div class="counter-container">
<h2>{{ count }}</h2>
<ion-button (click)="increment()">Increment</ion-button>
<ion-button (click)="decrement()">Decrement</ion-button>
<ion-button (click)="syncWithWidget()">Sync with Widget</ion-button>
</div>
</ion-content>
3. Add Logic for the Counter:
//home.page.ts
export class HomePage {
count = 0;
increment() {
this.count++;
}
decrement() {
this.count--;
}
syncWithWidget() {
if ((window as any).WidgetBridge) {
(window as any).WidgetBridge.syncCount(this.count);
} else {
console.error('WidgetBridge is not available.');
}
}
}
Step 2: Implement the Android Widget:
android/
└── app/
└── src/
└── main/
├── java/
│ └── com/
│ └── example/
│ └── counterapp/
│ ├── MainActivity.java
│ └── MyAppWidgetProvider.java
├── res/
│ ├── layout/
│ │ ├── widget_layout.xml
│ ├── drawable/
│ │ ├── widget_background.xml
│ ├── values/
│ │ ├── strings.xml
│ │ ├── colors.xml
│ │ └── styles.xml
├── AndroidManifest.xml
└── assets/
└── public/
1. Create Widget Layout:
android/app/src/main/res/layout/widget_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:background="@drawable/widget_background"
android:gravity="center"
android:elevation="6dp"
android:layout_margin="8dp">
<TextView
android:id="@+id/widget_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="Current Count"
android:textColor="@android:color/black"
android:fontFamily="sans-serif-medium"
android:layout_marginBottom="4dp"
android:shadowColor="#000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="3"/>
<TextView
android:id="@+id/widget_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="48sp"
android:text="0"
android:textColor="@android:color/black"
android:fontFamily="sans-serif-light"
android:shadowColor="#000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="3"/>
</LinearLayout>
2. Create a Background Drawable:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="135"
android:startColor="#80FFFFFF"
android:endColor="#80E0E0E0"
android:type="linear"/>
<corners android:radius="20dp"/>
<padding
android:left="16dp"
android:top="16dp"
android:right="16dp"
android:bottom="16dp"/>
</shape>
Step 3: Expose a JavaScript Interface in Android: To sync the count from your Ionic app to the widget, you need to expose a method in the native Android code.
1. Update MainActivity.java
:
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = getBridge().getWebView();
webView.addJavascriptInterface(new Object() {
@JavascriptInterface
public void syncCount(int count) {
syncWidgetCount(count);
}
}, "WidgetBridge");
}
private void syncWidgetCount(int count) {
Context context = getApplicationContext();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setTextViewText(R.id.widget_count, String.valueOf(count));
ComponentName widget = new ComponentName(context, MyAppWidgetProvider.class);
appWidgetManager.updateAppWidget(widget, views);
}
}
webView.addJavascriptInterface:
Adds a JavaScript interface named "WidgetBridge"
to the WebView.
syncCount(int count)
: This method is exposed to JavaScript and syncs the widget’s count with the app.
Step 4: Test the Integration
1. Build and Run Your App
ionic build
ionic capacitor sync android
ionic capacitor run android
2. Test the Widget Sync:
Use the counter buttons in your app, then tap the "Sync with Widget" button. The widget on your home screen should update to reflect the new count.
Subscribe to my newsletter
Read articles from Uttam Roy directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Uttam Roy
Uttam Roy
Hi, I'm Uttam From Bangladesh working as software engineer at Implevista.