Compare commits

..

No commits in common. "20c693004a9e09b0daa30fc0b636a327cbff9031" and "a02fd6c43072bc6583e685afa14fc9facb6f6a97" have entirely different histories.

15 changed files with 24 additions and 250 deletions

2
.fvmrc
View file

@ -1,3 +1,3 @@
{
"flutter": "3.24.4"
"flutter": "3.22.2"
}

View file

@ -14,10 +14,9 @@ java -jar bundletool-all-1.17.0.jar build-apks --bundle=my_app.aab --output=my_a
```
Download via:
![QR Code for APK](download_qr.jpg)
First launch you should see an incorrect text. Second launch it should update to the correct patched version. (After swiping away from recents)
First launch you should see an incorrect text. Second launch it should update to the correct patched version.
## Local development
@ -30,4 +29,4 @@ Steps:
alias f="fvm flutter"
alias flutter="fvm flutter"
```
- shorebird login
- shorebird login

View file

@ -37,12 +37,8 @@ android {
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
defaultConfig {

View file

@ -17,13 +17,6 @@
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"

View file

@ -1,55 +1,5 @@
package org.fnives.flutter.experiment_shorebird
import android.app.Activity
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Intent
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity : FlutterActivity() {
private val channel = "MainChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
channel
).setMethodCallHandler { call, result ->
when (call.method) {
Methods.RESTART.methodName -> {
val pendingIntent = PendingIntent.getActivity(
context,
4201,
if (isHomeApp()) Intent(intent.action).apply {
flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
intent.categories.forEach {
addCategory(it)
}
} else Intent(this, this::class.java).apply {
flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
},
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager
alarmManager[AlarmManager.RTC, System.currentTimeMillis() + 100] =
pendingIntent
if (context is Activity) {
(context as Activity).finishAndRemoveTask()
}
Runtime.getRuntime().exit(0)
result.success(Unit)
}
}
}
}
private fun isHomeApp(): Boolean {
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_HOME)
val res = packageManager.resolveActivity(intent, 0)
return res?.activityInfo != null && (packageName == res.activityInfo.packageName)
}
}
class MainActivity: FlutterActivity()

View file

@ -1,7 +0,0 @@
package org.fnives.flutter.experiment_shorebird
enum class Methods(val methodName: String) {
RESTART("restart");
}

View file

@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
android.enableJetifier=true

View file

@ -1,7 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip

View file

@ -19,7 +19,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version '1.9.20' apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
include ":app"

View file

@ -1,2 +1 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View file

@ -1,2 +1 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

View file

@ -1,109 +1,9 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shorebird_code_push/shorebird_code_push.dart';
void main() {
runApp(const MyApp());
}
class ShorebirdPatch extends StatefulWidget {
const ShorebirdPatch({super.key});
@override
State<StatefulWidget> createState() => _ShorebirdPatchState();
}
enum PatchState {
loading,
noUpdate,
updateReady;
}
enum MainChannelMethods {
restart(methodName: "restart");
final String methodName;
const MainChannelMethods({required this.methodName});
}
class _ShorebirdPatchState extends State<ShorebirdPatch> {
final shorebird = ShorebirdCodePush();
late Timer timer;
PatchState patchState = PatchState.noUpdate;
final methodChannel = const MethodChannel("MainChannel");
@override
void initState() {
timer = Timer.periodic(const Duration(minutes: 1), (timer) async {
checkForPatch(timer);
});
checkForPatch(timer);
super.initState();
}
Future<void> checkForPatch(Timer timer) async {
print('timer activated');
if (await shorebird.isNewPatchReadyToInstall()) {
print('timer await shorebird.isNewPatchReadyToInstall()');
setState(() {
patchState = PatchState.updateReady;
});
return;
}
if (!shorebird.isShorebirdAvailable()) {
print('timer !shorebird.isShorebirdAvailable()');
timer.cancel();
return;
}
if (!await shorebird.isNewPatchAvailableForDownload()) {
print('timer !await shorebird.isNewPatchAvailableForDownload()');
setState(() {
patchState = PatchState.noUpdate;
});
return;
}
final download = shorebird.downloadUpdateIfAvailable();
setState(() {
patchState = PatchState.loading;
});
await download;
if (await shorebird.isNewPatchReadyToInstall()) {
print('timer await shorebird.isNewPatchReadyToInstall()');
setState(() {
patchState = PatchState.updateReady;
});
return;
}
print('timer end');
}
@override
void dispose() {
timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
switch (patchState) {
case PatchState.loading:
return const SizedBox.square(dimension: 48, child: Center(child: CircularProgressIndicator()));
case PatchState.noUpdate:
return const SizedBox.shrink();
case PatchState.updateReady:
return InkWell(
child: const SizedBox.square(dimension: 48, child: Icon(Icons.update, size: 24)),
onTap: () {
methodChannel.invokeMethod(MainChannelMethods.restart.methodName);
},
);
}
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@ -122,7 +22,6 @@ class MyApp extends StatelessWidget {
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
@ -144,16 +43,11 @@ class _MyHomePageState extends State<MyHomePage> {
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
actions: const [ShorebirdPatch()],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'This is a release 1.9.1',
// 'You have times:',
),
const Text(
'You have pushed the button this many times:',
// 'You have times:',

View file

@ -57,14 +57,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
flutter:
dependency: "direct main"
description: flutter
@ -83,27 +75,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
@ -132,18 +119,18 @@ packages:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.12.0"
path:
dependency: transitive
description:
@ -152,30 +139,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
restart_app:
dependency: "direct main"
description:
name: restart_app
sha256: "00d5ec3e9de871cedbe552fc41e615b042b5ec654385e090e0983f6d02f655ed"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
shorebird_code_push:
dependency: "direct main"
description:
name: shorebird_code_push
sha256: "77511427c51906dd39d3bb1e6b0a8c49777975f9b0a5d073e35c9087a8a36bb6"
url: "https://pub.dev"
source: hosted
version: "1.1.6"
sky_engine:
dependency: transitive
description: flutter
@ -225,10 +188,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.0"
vector_math:
dependency: transitive
description:
@ -241,18 +204,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev"
source: hosted
version: "14.2.5"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "14.2.1"
sdks:
dart: ">=3.5.1 <4.0.0"
dart: ">=3.4.3 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View file

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.9.1+191
version: 1.0.0+10
environment:
sdk: '>=3.4.3 <4.0.0'
@ -30,8 +30,6 @@ environment:
dependencies:
flutter:
sdk: flutter
shorebird_code_push: ^1.1.4
restart_app: ^1.2.1
# The following adds the Cupertino Icons font to your application.

View file

@ -11,4 +11,4 @@ app_id: ee6ee5c7-8fb0-49a1-bdfd-eb326daf5ae5
# If auto_update: false, you will need to use package:shorebird_code_push to trigger updates.
# https://pub.dev/packages/shorebird_code_push
# Uncomment the following line to disable automatic updates.
auto_update: false
# auto_update: false