xCode error causing app to crash immediately after launch - ios

I am having an issue with my flutter app on iOS. It is working well on android and on web but I am getting this error on iOS. I come from a web dev background and do not have a lot of experience in iOS.
I am getting the error below and have zero idea of where to even begin. It appears to be an issue with one of the plugins... but I honestly have not idea. Any help on a direction would be incredibly helpful.
Error from xCode
This is a fairly large app
Here is my pubspec.
version: 1.6.0+18
environment:
sdk: ^2.7.0
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
http: ^0.13.0
responsive_builder: ^0.3.0
bloc: ^7.0.0
flutter_bloc: ^7.0.0
equatable: ^2.0.0
meta: ^1.1.6
hive: ^2.0.0
hive_flutter: ^1.0.0
flutter_appauth: ^0.9.2+6
intl: ^0.17.0
table_calendar: ^2.3.3
js: ^0.6.0
floating_action_bubble: ^1.1.2
badges: ^1.1.6
plaid_flutter:
git:
url: https://github.com/cwesterhold/plaid_flutter
ref: master
font_awesome_flutter: ^8.11.0
auth0_spa:
git:
url: https://github.com/cwesterhold/auth0-spa-flutter
ref: master
multiple_select:
git:
url: https://github.com/cwesterhold/multiple_select
ref: master
#catcher: ^0.6.2
flutter_localizations:
sdk: flutter
#package_info_plus: ^1.0.0
purchases_flutter: ^3.0.0
url_launcher: ^6.0.0
syncfusion_flutter_charts: ^18.4.47
progress_indicator: ^0.1.1
uuid:
dev_dependencies:
flutter_test:
sdk: flutter
hive_generator:
build_runner: ^1.10.0
flutter_launcher_icons: ^0.9.0
flutter_icons:
image_path: 'assets/ic_launcher.png'
android: false
ios: true
#flutter pub run flutter_launcher_icons:main
flutter:
uses-material-design: true
assets:
- assets/
fonts:
- family: Comfortaa
fonts:
- asset: fonts/Comfortaa-VariableFont_wght.ttf
Here is the main
import 'dart:async';
import 'package:clicket/bloc/theme/theme.dart';
import 'package:clicket/models/errorModel.dart';
import 'package:clicket/screens/login/loginMain.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() async {
bool isInDebugMode = false;
assert(isInDebugMode = true);
ErrorModel errorModel = ErrorModel();
WidgetsFlutterBinding.ensureInitialized();
bool isDev = false;
assert(isDev = true);
if (isDev == true) {
runApp(Clicket());
} else {
runZoned<Future<void>>(
() async {
runApp(Clicket());
},
onError: (dynamic error, StackTrace stackTrace) {
errorModel.reportError(error, stackTrace);
// Send report
},
);
}
}
class Clicket extends StatefulWidget {
#override
_ClicketState createState() => _ClicketState();
}
class _ClicketState extends State<Clicket> {
var s;
ThemeBloc _themeBloc = ThemeBloc();
final navigatorKey = GlobalKey<NavigatorState>();
#override
Widget build(BuildContext context) {
// make sure to close out all blocs to prevent memory leaks
#override
void dispose() {
_themeBloc.close();
super.dispose();
}
// Includes all blocs so they are available across the entire application
return BlocProvider<ThemeBloc>(
create: (context) => _themeBloc,
child: BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
if (state is ThemeStart) {
_themeBloc.add(CheckTheme());
} else if (state is ThemeLight) {
s = state.themeData;
} else if (state is ThemeDark) {
s = state.themeData;
}
return MaterialApp(
navigatorKey: navigatorKey,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
],
debugShowCheckedModeBanner: false,
title: "Clicket - Personal Budgeting",
onGenerateRoute: (rt) {
return MaterialPageRoute(
builder: (context) {
return LoginMain();
},
);
},
theme: s,
);
},
),
);
}
}
If I remove the LogIn route and rerun it in xCode, I get this.
Second xCode error
Which is just as cryptic....
When I run things through android studio it doesnt give any insights at all...
NOthing in Android Studio
Even if I remove everything except for a basic scaffold, I still get the same second error as above. But if I create a new project with the same pubspec, it works just fine.
Any help would be greatly appreciated.

So I found the issues...
it had to do with a bad line in the info.plist file.
I had this..
<key>NSAppTransportSecurity</key>
<true/>
and it should be this...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Lesson learned - dont just blindly copy code you find on the internet :-)

Related

Flutter: url_launcher package can not encode body for sms

i using url_launcher package to redirect from my app to SMS. i wanna passing content of SMS but it's display like this
enter image description here
version:
Iphone OS: 15.6
Flutter: 3.0.5
url_launcher: ^6.1.5
my code
Future<void> sendSMS(String registerSyntax) async {
final Uri smsLaunchUri = Uri(
scheme: 'sms',
path: '0123456789',
queryParameters: <String, String>{
'body': Uri.encodeComponent(registerSyntax),
},
);
if (!await launchUrl(smsLaunchUri)) {
throw 'Could not launch $smsLaunchUri';
}
}

React native: TypeError: null is not an object (evaluating 'SplashScreen.preventAutoHide')

My react native app was working just fine before I used expo eject. I ejected it because I now intend to build and release the app to the ios app store. As soon as I attempt to start the ejected app using react-native run-ios after it's been ejected I get the exception below.
Please could someone help to understand what's causing this issue and how to tackle it?
react Native versions as follows:
react-native-cli: 2.0.1
react-native: 0.61.5
TypeError: null is not an object (evaluating 'SplashScreen.preventAutoHide')
This error is located at:
in AppLoading (at AppLoading.js:52)
in AppLoading (at App.js:464)
in App (at renderApplication.js:40)
in RCTView (at AppContainer.js:101)
in RCTView (at AppContainer.js:119)
in AppContainer (at renderApplication.js:39)
preventAutoHide
SplashScreen.js:4:21
AppLoading#constructor
AppLoadingNativeWrapper.js:6:8
renderRoot
[native code]:0
runRootCallback
[native code]:0
renderApplication
renderApplication.js:52:52
runnables.appKey.run
AppRegistry.js:116:10
runApplication
AppRegistry.js:197:26
callFunctionReturnFlushedQueue
[native code]:0
The AppLoading component is not available in the bare workflow. As #gaurav-roy said you have to refactor your code.
Install the expo-splash-screen package with npm install expo-splash-screen
Add a splash-screen to your Android and iOS projects. Run npm run expo-splash-screen --help and follow the instructions of this CLI tool. (Because of a bug you might have to run the command again with the -p "ios" flag if it only adds the SplashScreen for Android after running it.
Change your code inside App.tsx in a similar way as in this example.
If you're working with hooks you probably want to add an useEffect
hook with an empty dependency list which runs an async function. Here an example of how it could be done:
const App = (props: Props) => {
const [isLoadingComplete, setLoadingComplete] = useState(false);
const init = async () => {
try {
// Keep on showing the SlashScreen
await SplashScreen.preventAutoHideAsync();
await loadResourcesAsync();
} catch (e) {
console.warn(e);
} finally {
setLoadingComplete(true);
// Hiding the SplashScreen
await SplashScreen.hideAsync();
}
useEffect(() => {
init();
}, []);
const renderApp = () => {
if (!isLoadingComplete && !props.skipLoadingScreen) {
return null;
}
return (
<Main />
);
};
return <StoreProvider>{renderApp()}</StoreProvider>;
}
As its evident from docs , SplashScreen is an inbuilt api for expo apps, and since you ejected it , it throws an error since it cant be used.
You can see this in the docs expo splashscreen .
First you should download npm i expo-splash-screen
And then change your import statement to :
import * as SplashScreen from 'expo-splash-screen';
Hope it helps. feel free for doubts
After looking through this SO page and then digging into some links, especially this expo page where they kind of provide a solution for this, I was able to get my app running after about 3 hours of struggle. They haven't added any functional component example, so I am sharing my code below in case someone came here looking for the solution.
import { Asset } from "expo-asset";
import * as Font from "expo-font";
import React, { useState, useEffect } from "react";
import { Platform, StatusBar, StyleSheet, View } from "react-native";
import { Ionicons } from "#expo/vector-icons";
import * as SplashScreen from 'expo-splash-screen';
import AppNavigator from "./navigation/AppNavigator";
export default props => {
const [isLoadingComplete, setLoadingComplete] = useState(false);
const theme = {
...DefaultTheme,
roundness: 2,
colors: {
...DefaultTheme.colors,
primary: "#E4002B",
accent: "#E4002B",
},
};
useEffect(() => {
async function asyncTasks() {
try {
await SplashScreen.preventAutoHideAsync();
} catch (e) {
console.warn(e);
}
await loadResourcesAsync()
setLoadingComplete(true);
}
asyncTasks()
}, []);
return (
!isLoadingComplete && !props.skipLoadingScreen ? null :
<View style={styles.container}>
{Platform.OS === "ios" && <StatusBar barStyle="default" />}
<AppNavigator />
</View>
);
}
async function loadResourcesAsync() {
await Promise.all([
Asset.loadAsync([
require("./assets/images/logo.png") // Load your resources here (if any)
]),
Font.loadAsync({
// You can remove this if you are not loading any fonts
"space-mono": require("./assets/fonts/SpaceMono-Regular.ttf"),
}),
]);
await SplashScreen.hideAsync();
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
});
This solved it for me for an ejected expo app. Looks like expo was referencing it wrongly.
https://github.com/expo/expo/issues/7718#issuecomment-610508510
What worked for me was updating node_modules/expo/build/launch/splashScreen.js to the following as suggested by adamsolomon1986 in the repo (issue #7718):
import { NativeModules } from 'react-native';
import* as SplashScreen from 'expo-splash-screen'
export function preventAutoHide() {
if (SplashScreen.preventAutoHide) {
SplashScreen.preventAutoHide();
}
}
export function hide() {
if (SplashScreen.hide) {
SplashScreen.hide();
}
}
//# sourceMappingURL=SplashScreen.js.map

Login with facebook error on iOS in flutter project

I wrote a flutter login with facebook app.
It works correctly on Android.
On iOS simulator and on real iPhone device it does not work. Both having iOS 13.2.
pub spec.yaml file
firebase_auth: ^0.6.6
flutter_facebook_login: ^1.1.1
flutter_auth_buttons: ^0.3.1
main.dart file
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
import 'package:flutter_auth_buttons/flutter_auth_buttons.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
FirebaseAuth _auth = FirebaseAuth.instance;
bool isLogged = false;
FirebaseUser myUser;
Future<FirebaseUser> _loginWithFacebook() async {
var facebookLogin = new FacebookLogin();
var result = await facebookLogin.logInWithReadPermissions(['email']);
debugPrint(result.status.toString());
if (result.status == FacebookLoginStatus.loggedIn) {
FirebaseUser user =
await _auth.signInWithFacebook(accessToken: result.accessToken.token);
return user;
}
return null;
}
void _login() {
_loginWithFacebook().then((response) {
if (response != null) {
myUser = response;
setState(() {
isLogged = true;
});
}
});
}
void _logout() async {
await _auth.signOut().then((response) {
setState(() {
isLogged = false;
});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Login App',
home: Scaffold(
appBar: AppBar(
title: Text(isLogged ? 'Profile Page' : 'Login App'),
actions: <Widget>[
IconButton(
onPressed: _logout,
icon: Icon(Icons.power_settings_new),
)
],
),
body: Center(
child: isLogged
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Name: ' + myUser.displayName),
Image.network(myUser.photoUrl),
],
)
: FacebookSignInButton(
onPressed: _login,
),
),
),
);
}
}
I added the plist file in the Xcode project correctly. And configured the iOS version of the Facebook developer correctly based on the following steps:
https://developers.facebook.com/docs/facebook-login/ios
I changed the project workspace settings in Xcode between Legacy build and new build system. I still get error.
I tried to add the following to the pod file, and still get error
pod 'FBSDKCoreKit', '~> 4.44'
And even all proposed solutions in here
How to fix build error with FBSDKLoginKit in Xcode
The error that I get is
No known class method for selector 'dictionary:setObject:forKey:'
I also tried to change the Firebase version and the Facebook Flutter login version in pub spec file (between 1.1.1 and 1.2.0 because I do not want to use AndroidX) but still getting the error.
Note that I updated Xcode to latest version, and error was not fixed.
I changed the iOS deployment version in Xcode for all pods to version 8. And error not fixed!
UPDATE (JULY 2020)
You can use a new package that works for both Android and iOS:
flutter_login_facebook
If you want to use the flutter_facebook_login, below is a solution:
UPDATE (APRIL 2020)
Add flutter_facbook_login version 3.0.0 from pub.dev to your flutter project
Create your app on Facebook developers and configure your flutter app accordingly
Change your iOS target version to 9 in Xcode
Open in terminal the Podfile.lock which is located in the iOS folder of your flutter project and change all facebook api versions to 5.8.0. If the Podfile.lock does not exist, run your app once (so the file is created) and after it fires an error edit Podfile.lock then run it again. If your app still fails, run pod install manually form terminal.
There are two problems:
the compatibility between Facebook Login API and Firebase.
iOS update to version 13.x.
In pubspec.yaml file updated the firebase version to latest version.
Also, I am using version 1.2.0 for facebook login but still 1.1.1 works.
firebase_auth: ^0.14.0+5
flutter_facebook_login: ^1.2.0
flutter_auth_buttons: ^0.3.1
I opened Runner.xcworkspace in Xcode (located in iOS folder inside flutter project), then File->WorkSpace settings, and selected New Build System option.
For all pods, change iOS deployment version to 8.0 (or above).
Now the application builds successfully and runs on iOS. But I get CancelledByUser each time I click on the Login with Facebook button.
This is a bug when having iOS update 13.x running the facebook login api.
I found a turnaround that made the login works.
final facebookLogin = new FacebookLogin();
facebookLogin.loginBehavior = FacebookLoginBehavior.webViewOnly;
You can directly use my function as it works on both android and iOS and also registers the user in firebase console.
I have simply opening the login page in the WebView and when the user register himself, I am storing the credential in the firebase and then printing his name .
final FacebookLogin fblogin = FacebookLogin();
FirebaseAuth auth = FirebaseAuth.instance;
Future loginwihFacebook() async {
fblogin.loginBehavior = FacebookLoginBehavior.webViewOnly;
final result = await fblogin.logInWithReadPermissions(["email"]);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
final token = result.accessToken.token;
await auth.signInWithCredential(FacebookAuthProvider.credential(token));
var url =
'https://graph.facebook.com/v2.12/me?fields=name,first_name,picture,last_name,email&access_token=$token';
var graphapiresponse = await http.get(url);
var profileData = jsonDecode(graphapiresponse.body);
var name = profileData["name"];
print(name);
break;
case FacebookLoginStatus.cancelledByUser:
print("cancelled by user");
break;
case FacebookLoginStatus.error:
print("error");
break;
}
}

How do I open an external url in flutter web in new tab or in same tab

I have a simple web app I have created with flutter web. I would like to know how I can open new an external url either in a new tab or in the same tab in my flutter web app. say I want to open the url https://stackoverflow.com/questions/ask
I think you want this — dart:js enables interoperability between Dart and JS —:
import 'dart:js' as js;
// ...
FlatButton(
child: Text('Button'),
onPressed: () {
js.context.callMethod('open', ['https://stackoverflow.com/questions/ask']);
},
)
One simple way is to just create a button and use dart:html's window.open() method:
import 'dart:html' as html;
// ...
html.window.open('https://stackoverflow.com/questions/ask', 'new tab');
The name parameter — which I left as 'new tab' — refers to the new tab's window name, about which you can learn more from MDN's documentation.
https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_web
url_launcher has been the solution for android and ios, recently it added support for web.
You can use the url_launcher plugin
Then in your code
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher_string.dart';
void main() {
runApp(Scaffold(
body: Center(
child: RaisedButton(
onPressed: _launchURL,
child: Text('Show Flutter homepage'),
),
),
));
}
_launchURL() async {
const url = 'https://flutter.io';
if (await canLaunchUrlString(url)) {
await launchUrlString(url);
} else {
throw 'Could not launch $url';
}
}
Example taken from the package site
As of url_launcher: ^6.1.0 The plugin introduces support for webOnlyWindowName property and few Other new apis like launchUrl, For web support now you longer have to depend on dart:html You can simply declare the below function
Future<void> launchLink(String url, {bool isNewTab = true}) async {
await launchUrl(
Uri.parse(url),
webOnlyWindowName: isNewTab ? '_blank' : '_self',
);
}
and use it like this
onTap:(){
launchLink('https://stackoverflow.com/questions/ask', isNewTab: true)
}
Answered here https://stackoverflow.com/a/56656885/361832
Flutter Web does not support plugins (yet), so you have to use replacements from dart:html
https://api.dartlang.org/stable/2.4.0/dart-html/Window/open.html window.open(url, 'tab');
or
https://api.dartlang.org/stable/2.4.0/dart-html/Window/location.html window.location.assign(url);
Extending the answer of #xuyanjun which works fine when to want to open an external link from flutter web to a new tab. But if you want to open an external link to the website in the same tab in which the flutter web app is currently running.
then you can do it like this.
import 'dart:js' as js;
// ...
FlatButton(
child: Text('Button'),
onPressed: () {
js.context.callMethod('open', ['https://blup.in/','_self']); //<= find explanation below
},
)
Explanation :- dart:js package from flutter provide the functionality to call web-specific functions like open function from flutter and all the strings in the list are parameter which are passed to the function refer this.
So if you want to open new tab then not need to pass seconds parameter but if you wan to open in same tab then pass _self as second parameter.
You can use the below code to launch the URL in the same tab.
window.top.location.href = '<your url>'
Must import
import 'dart:html';
package url_launcher now has web support.
just import url_launcher_web, and url_launcher to your pubspec.yaml
import 'package:url_launcher/url_launcher.dart';
const String _url = 'https://flutter.dev';
void _launchURL() {
launch(_url);
}
To launch URL you need to import url_launcher with latest version and you are good to launch URL through following code:
//Launch Github
_launchGithub() async {
const url = 'https://github.com/Pranav2918'; //Paste your URL string here
if (await canLaunchUrlString(url)) {
await launchUrlString(url);
} else {
throw 'Could not launch $url';
}
}
For non string URLs:
Another approach :
final Uri _url = Uri.parse('https://flutter.dev');
Future<void> _launchUrl() async {
if (!await launchUrl(_url)) {
throw 'Could not launch $_url';
}
}
Happy Fluttering !!

How to display an HTML asset file?

I have an .html file in my assets directory.
How can I display / render it in Flutter?
The package from the Flutter Team was released yesterday:
webview_flutter
How to load local asset:
Add the file to the project and update your pubspec:
//...
assets:
//...
- assets/yourFile.html
//...
In your widget:
child: FutureBuilder<String>(
future: LocalLoader().loadLocal(),
builder: (context, snapshot) {
if (snapshot.hasData) {
// return Text("${snapshot.data}");
return WebView(
initialUrl: new Uri.dataFromString(snapshot.data,
mimeType: 'text/html')
.toString(),
// maybe you Uri.dataFromString(snapshot.data, mimeType: 'text/html', encoding: Encoding.getByName("UTF-8")).toString()
javascriptMode: JavascriptMode.unrestricted,
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
Loading the text from the file:
class LocalLoader {
Future<String> loadLocal() async {
return await rootBundle.loadString('assets/yourFile.html');
}
}
You can use the flutter_webview_plugin this should work with local files too.
It works both on Android and iOS
Dart
var flutterWebviewPlugin = new FlutterWebviewPlugin();
flutterWebviewPlugin.launch("https://flutter.io");
await flutterWebviewPlugin.onDestroy.first;
Android Manifest
<activity android:name="com.flutter_webview_plugin.WebviewActivity"
android:parentActivityName=".MainActivity"/>
Unzip the apk package. I found the reason: path is wrong
For Android:
"assets/test.html" == "file:///android_asset/flutter_assets/assets/test.html"
so, just like this:
WebView(
initialUrl: "file:///android_asset/flutter_assets/assets/test.html",
javascriptMode: JavascriptMode.unrestricted,
)
you can load assets/test.html.
You can try my flutter_inappbrowser plugin (EDIT: it has been renamed to flutter_inappwebview), that is a Flutter Plugin that allows you to add an inline webview integrated with the widget tree or open an in-app browser window!
You can use the InAppWebView widget class or the InAppBrowser class and use its webview controller.
In your case, you can use the InAppWebViewController.loadFile method.
To be able to load your local files (html, js, css, etc.), you need to add them in the assets section of the pubspec.yaml file, otherwise they cannot be found!
Example of a pubspec.yaml file:
...
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/index.html
- assets/css/
- assets/images/
...
Then, call the method in your business logic:
inAppWebViewController.loadFile("assets/index.html");
or
InAppWebView(
onWebViewCreated: (InAppWebViewController controller) {
var uri = "assets/index.html"
controller.loadFile(assetFilePath: uri);
},
),
If you just need to render simple HTML tags (p,img,a,h1,etc.) you could try this flutter_html plugin
It's not mature enough for production yet IMHO but worth considering / contributing.

Resources