How to get build and version number of Flutter app - flutter

I am currently developing an application which is currently in beta mode. Due to this, I would like to show them what version they are on. For example, "v1.0b10 - iOS". So far, I have got this code: Text("Build: V1.0b10 - " + (Platform.isIOS ? "iOS" : "Android")). How would I be able to get the build version and number within flutter?

You can use package_info_plus.
The versions are extracted from:
Android:
build.gradle, versionCode and versionName
iOS:
Info.plist, CFBundleVersion
Usage
Add the dependency
Add this to your package's pubspec.yaml file:
dependencies:
package_info_plus: ^1.0.6
Import the file into your dart file:
import 'package:package_info_plus/package_info_plus.dart';
if your method is marked as async:
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appName = packageInfo.appName;
String packageName = packageInfo.packageName;
String version = packageInfo.version;
String buildNumber = packageInfo.buildNumber;
If you don't want to use await/async:
PackageInfo.fromPlatform().then((PackageInfo packageInfo) {
String appName = packageInfo.appName;
String packageName = packageInfo.packageName;
String version = packageInfo.version;
String buildNumber = packageInfo.buildNumber;
});

Note: This answer has been updated to reflect the fact that the package_info plugin is deprecated and redirects to package_info_plus.
Version name and build number
At development time, you can easily find the version name and build number of a Flutter or Dart project by inspecting pubspec.yaml. Here is an example:
version: 1.1.0+2
This is case the version name is 1.1.0 and the build number is 2.
However, if you want to get these values at runtime, you should use a plugin.
Add the dependency
In pubspec.yaml add the package_info_plus package.
dependencies:
package_info_plus: ^1.0.2
Update the version number to the current one.
Import the package
In the file that you need it, add the following import.
import 'package:package_info_plus/package_info_plus.dart';
Get the version name and code
In your code you can get the app version name and code like this:
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String version = packageInfo.version;
String code = packageInfo.buildNumber;
See also
How to set build and version number of Flutter app
How to get build and version number of Flutter Web app

install package_info_plus, then you can use it directly with future builder in your widget tree:
FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
return Align(
alignment: Alignment.bottomCenter,
child: Text(
'Version: ${snapshot.data!.version}',),
);
default:
return const SizedBox();
}
},
),

RE the multiple references to package_info, please note that this package has been deprecated and the recommended replacement is the Flutter Community Plus Plugins version, package_info_plus.

You can try new_version plugin. Using this plugin you can get installed App Version, Playstore App Version and app url which can redirect to playstore.
New Version Plugin
void versionCheck() async {
final NewVersion newVersion = NewVersion(context: context);
VersionStatus versionStatus = await newVersion.getVersionStatus();
if (versionStatus != null && versionStatus.canUpdate) {
await ConfirmDialog(
context: context,
title: 'Update Available',
body: Text('A new version, ${versionStatus.storeVersion}, is available.'),
acceptButton: 'Update Now',
cancelButton: 'Update Later'
).then((ConfirmAction res) async {
if (res == ConfirmAction.CONFIRM && await canLaunch(versionStatus.appStoreLink)) {
await launch(versionStatus.appStoreLink, forceWebView: false);
}
});
}
}
Custom Alert Dialog Box
enum ConfirmAction{ CONFIRM, CANCEL }
Future<ConfirmAction> ConfirmDialog({
BuildContext context,
String title,
Widget body,
String acceptButton,
String cancelButton
})
=> showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) => AlertDialog(
title: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
children: <Widget>[
Text(title)
],
),
content: Wrap(
runSpacing: 10,
children: <Widget>[
body,
],
),
actions: <Widget>[
FlatButton(
padding: EdgeInsets.all(6),
child: Text(acceptButton ?? 'Confirm'),
onPressed: (){
Navigator.of(context, rootNavigator: true).pop(ConfirmAction.CONFIRM);
}
),
FlatButton(
padding: EdgeInsets.all(6),
child: Text(cancelButton ?? 'Cancel'),
onPressed: (){
Navigator.of(context, rootNavigator: true).pop(ConfirmAction.CANCEL);
}
),
],
)
);

For using it from command line or CLI, you need a pure Dart code.
I used the following script:
// ignore_for_file: avoid_print
import 'dart:io';
import 'package:path/path.dart';
import 'package:yaml/yaml.dart';
String pathToYaml = join(dirname(Platform.script.toFilePath()), '../pubspec.yaml');
Future<YamlMap> loadPubspec() async => loadYaml(await File(pathToYaml).readAsString());
void main() async {
var pubspec = await loadPubspec();
print(pubspec['version'].toString().split('+')[0]);
}
You can run it from the project root folder:
dart run scripts/get_version_name.dart

In Flutter mobile applications the version number is in pubspec.yaml file. like below:
version: 1.0.0+1
To get the version name and code, add the package_info dependency into pubspec.yaml file, like below:
dependencies:
package_info: ^0.4.0+16
And
import 'package:package_info/package_info.dart'; // import the package_info
Future<void> _initPackageInfo() async {
final _packageInfo = await PackageInfo.fromPlatform();
setState(() {
String AppName = _packageInfo.appName;
String PackageName = _packageInfo.packageName;
String AppVersion = _packageInfo.version;
String BuildNumber = _packageInfo.buildNumber;
String BuildSignature = _packageInfo.buildSignature;
});
}

Related

Flutter open_file.dart not opening pdf file

Im noob in flutter, i try to recreate this proses,create, save then launch pdf, this app has 2 dart file:
1. main.dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdf/pdf.dart';
import 'mobile.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {...}
class MyHomePage extends StatefulWidget {...}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: Text('Cliick Me'),
onPressed: _createPDF,
),
),
);
}
Future<void> _createPDF() async {
PdfDocument document = PdfDocument();
final page = document.pages.add();
page.graphics.drawString(
'welcome',
PdfStandardFont(PdfFontFamily.helvetica, 30)
);
List<int> bytes = document.save();
document.dispose();
//FileSaveHelper.saveAndLaunchFile(bytes, 'Outfile.pdf');
saveAndLaunchFile(bytes, 'Outfile.pdf');
}
2.mobile.dart
import 'dart:io' as io;
import 'dart:io';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
Future<void> saveAndLaunchFile(List<int> bytes, String fileName) async {
try {
final path = (await getExternalStorageDirectory())!.path;
print('filepath : $path/$fileName');
String data='empty';
print('data pos1= $data');
data = (await io.File('$path/$fileName').exists()).toString();
final file = File('$path/$fileName');
await file.writeAsBytes(
bytes,
flush: true
);
print('data pos2= $data');
OpenFile.open('$path/$fileName');
print('done');
}
catch (e) {
print('error : $e');
}
}
Now when I press 'click me', it does nothing, it supposed to show 'welcome' String from main.dart
the output from mobile.dart are bellow:
Syncing files to device Android SDK built for x86...
Reloaded 1 of 955 libraries in 310ms.
I/flutter ( 3688): filepath : `/storage/emulated/0/Android/data/com.cg2.my_first_try/files/Outfile.pdf`
I/flutter ( 3688): data pos1= empty
I/flutter ( 3688): data pos2= true
I/flutter ( 3688): done
The funny things, the day before, when i first install android studio, flutter and run this program, it was working. Then I updated dependency on yaml file, then on this perticular line on mobile.dart, asking
final path = (await getExternalStorageDirectory()).path; generate error ....potentialy null.
so i change into :
final path = (await getExternalStorageDirectory())!.path;
lastly, iam using ubuntu 20.04, i just need to understand whats going on, is it androdi studio or emulator problem, or do linux need permision to getExternalStorageDirectory. Thanks.
Its seem ths java version that causing this. after googling, it turns out openJdk16 has campatible issues, messing up gradle creation. So i downgrade to 11, so far looks good.
To use jdk 16 you should upgrade to:
android/gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
android/build.gradle
classpath 'com.android.tools.build:gradle:7.0.1'
my jdk
java 16.0.1 2021-04-20
Java(TM) SE Runtime Environment (build 16.0.1+9-24)
Java HotSpot(TM) 64-Bit Server VM (build 16.0.1+9-24, mixed mode, sharing)

Perform in app force update using current and required build numbers

I want to force update my app.
Here's what I have done so far.
Obtained the current build version of my app using package_info_plus
Obtained the enforced build version which I have stored in the firebase remote config. So I used this package: firebase_remote_config
I then compared the two build numbers to see if the update is needed. What should I do after that?
Here's my code:
void initState(){
super.initState();
checkForUpdate();
_initPackageInfo();
_enforcedVersion();
if(int.parse(_packageInfo.buildNumber) > int.parse(enforcedBuildNumber))
{
//How to force update?
}
}
Future<void> _initPackageInfo() async {
final info = await PackageInfo.fromPlatform();
setState(() {
_packageInfo = info;
});
}
Future<void> _enforcedVersion() async {
final RemoteConfig remoteConfig = RemoteConfig.instance;
await remoteConfig.setConfigSettings(RemoteConfigSettings(
fetchTimeout: const Duration(seconds: 10),
minimumFetchInterval: Duration.zero,
));
await remoteConfig.fetchAndActivate();
setState(() {
enforcedBuildNumber = remoteConfig.getString('enforced_build_number');
});
}
You could display a non dismissable dialog which would ask the user to update the application with a redirection button to the device appstore.
By using a package such as url_launcher you can easily do that:
Code Sample
import 'dart:io' show Platform;
import 'package:url_launcher/url_launcher.dart';
// You can show a dialog like this
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => AlertDialog(
title: Text('Please update your app'),
actions: [
TextButton(
onPressed: launchAppStore,
child: Text('Open App Store'),
),
],
),
);
// Method to open the appstore
void launchAppStore() {
/// Depending on where you are putting this method you might need
/// to pass a reference from your _packageInfo.
final appPackageName = _packageInfo.packageName;
if (Platform.isAndroid) {
launch("https://play.google.com/store/apps/details?id=$appPackageName");
} else if (Platform.isIOS) {
launch("market://details?id=$appPackageName");
}
}

Flutter pdf file isnt saving and showing error

I am trying to simple generate and save pdf issue is its showing error in my code
I am doing like this
import 'package:path_provider/path_provider.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
onTap: () async{
final pdf = pw.Document();
pdf.addPage(
pw.Page(
build: (pw.Context context) => pw.Center(
child: pw.Text('Hello World!'),
),
),
);
// Share.shareFiles([pdf], text: 'Reports');
final output = await getTemporaryDirectory();
final path = "${output.path}/temp.pdf";
final file = File(path); // here its showing error 2 positional
await file.writeAsBytes(pdf.save()); // here its showing The method 'writeAsBytes' isn't defined for the type 'File'.
},
Plugin versions
pdf: 2.1.0 & path_provider: ^2.0.2
I search every where but I didnt find any solution cant find it so why I am getting this error -_-
Use io library to write the file:
import 'dart:io' as io;
onTap: () async{
final pdf = pw.Document();
pdf.addPage(
pw.Page(
build: (pw.Context context) => pw.Center(
child: pw.Text('Hello World!'),
),
),
);
// Share.shareFiles([pdf], text: 'Reports');
//replace your code to save file from bellow
final output = await getTemporaryDirectory();
final path = "${output.path}/temp.pdf";
final file = await io.File(path).writeAsBytes(pdf.save());
},
The error would be due to methods defined in the pdf library. You can use default io library to solve that.

Undefined name 'navigator' in flutter

I have a StatefulWidget for page in flutter. On the press of a button I call the following method:
IconButton(
icon: Icon(Icons.photo),
iconSize: 25.0,
color: Theme.of(context).primaryColor,
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CallPage(title:contact)),
);
},
),
CallPage is another statefulWidget from which I am trying to create local and remote RTCVideoRenderers.
I use the following code to get the userMedia: video and audio from the navigator.
_getUserMedia() async {
final Map<String, dynamic> mediaConstraints = {
'audio': false,
'video': {'facingMode': 'user'}
};
if(await Permission.camera.request().isGranted) {
if(await Permission.microphone.request().isGranted){
MediaStream _localStream = await navigator.getUserMedia(mediaConstraints);
_localRenderer.srcObject = _localStream;
return _localStream;
}
}
}
Here, the Dart Analysis is throwing an error:
error: Undefined name 'navigator'. (undefined_identifier at [chatapp] lib/home/call_page.dart:99)
I am going crazy now! This exact app was working a few minutes ago. Suddenly it stopped working.
I have tried deleting the build directory, running flutter clean, restarting the project, everything!!
Please HELP!
The class name navigator has changed to MediaDevices in the flutter-webrtc package just on the day before this question was asked! Hope it helps someone.

Dart http package is not working in built apk

I'm developing a Flutter application that needs to make http requests. I installed the http package as usual, but when it came time to test the app in a real device, the http requests are hanging, I never get a response or status code. I decided then to start a new application just to mess around with http package, but still I got the same issue.
This is what I get while debugging in Android Emulator (I get a response almost immediately) and this is what I get on a real device (hanging forever).
Possible solutions I have already tried: built signed and unsigned apk, ran flutter clean before building apk, built apk using --no-shrink flag, changed the version of http package in pubspec.yaml, and none of these seemed to solve the issue.
I am using the latest stable version of Flutter SDK (v1.17.5), Android Studio for coding, and Ubuntu 20.04 as Operating System.
Here is my dart code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class AuthScreen extends StatefulWidget {
#override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
final TextEditingController _urlController = TextEditingController();
String _status = 'Waiting for request';
void _submit() async {
setState(() {
_status = 'Waiting for response...';
});
var response = await http.get(_urlController.text);
if (response.statusCode == 200) {
setState(() {
_status = response.body.substring(0, 40) + ' [...]';
});
} else {
_status = 'Something went wrong';
}
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
controller: _urlController,
),
FlatButton(
child: Text('Send request'),
onPressed: _submit,
),
Text(_status)
],
),
),
);
}
}
Here is my pubspec.yaml, in case it's useful:
name: testingHttpPackage
description: A new Flutter application.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
http: ^0.12.1
cupertino_icons: ^0.1.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
Did you mention internet permission in AndroidManifest.xml file?
In android/app/src/main/, there is AndroidManifest.xml file, put the below line after manifest tag i.e. after the first tag.
<uses-permission android:name="android.permission.INTERNET" />