i have got runtime error "invalid internet address" but the api works fine .
Exception has occurred.
HttpException (HttpException: , uri = https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=d2c9e9553c4647f3add970ed74a812ee)
class News {
List<ArticleModel> news = [];
Future<void> getNews() async {
String url;
url = "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=d2c9e9553c4647f3add970ed74a812ee";
var response = await http.get(Uri.parse(url));
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == "ok") {
jsonData["articles"].forEach((element) {
if (element['urlToImage'] != null && element['description'] != null) {
ArticleModel articleModel = ArticleModel(
title: element['title'],
author: element['author'],
description: element['description'],
urlToImage: element['urlToImage'],
// publshedAt: DateTime.parse(element['publishedAt']),
content: element["content"],
url: element["url"],
);
news.add(articleModel);
}
});
}
}
}
The code worked for me after this change:
Future<void> getNews() async {
var url = Uri.parse('https://newsapi.org/v2/top-headlines?country=eg&apiKey=api');
var response = await http.get(url);
Related
I am working with GraphQL. I need to pass parameters to Http headers. However, I see an option to pass only normal parameters (code below). PLEASE tell me how to do it!!
Query(
options: QueryOptions(
document: gql(userGraphQL),
variables: {
"..." : "..."
}
),
builder: ...
)
I have created this file to related the GraphQL
gql_utils.dart file
class GraphQLUtils {
static final GraphQLUtils _instance = GraphQLUtils._internal();
GraphQLClient? _client;
factory GraphQLUtils() {
return _instance;
}
GraphQLUtils._internal() {
final httpLink = HttpLink(
'your base url',
);
final authLink = AuthLink(
ignore: undefined_identifier
getToken: () async => 'Bearer $YOUR_PERSONAL_ACCESS_TOKEN',
);
var link = authLink.concat(httpLink);
var link = httpLink;
var link = httpLink;
final policies = Policies(
fetch: FetchPolicy.networkOnly,
);
_client = GraphQLClient(
cache: GraphQLCache(),
link: link,
defaultPolicies: DefaultPolicies(
watchQuery: policies,
query: policies,
mutate: policies,
),
);
}
Future<Map<String, dynamic>> queryRepo(
DocumentNode readRepositories, map) async {
final options = WatchQueryOptions(
document: readRepositories,
variables: map,
pollInterval: const Duration(seconds: 4),
fetchResults: true,
);
QueryResult result = await _client!.query(options);
if (result.hasException) {
Map<String, dynamic> response = <String, dynamic>{};
response['success'] = false;
response['message'] = result.exception!.graphqlErrors[0].message;
return response;
} else {
Map<String, dynamic> response = <String, dynamic>{};
response['success'] = true;
response['data'] = result.data;
return response;
}
}
}
this is Example query class
class UserQueries {
static final userInsertQuery = gql(r'''
mutation Insert_users($objects: [users_insert_input!]!, $onConflict: users_on_conflict) {
insert_users(objects: $objects, on_conflict: $onConflict) {
returning {
id
name
timestamp
}
}
}
''');
}
and how to call api
Future insertUserApi(String name) async {
try {
Map<String, dynamic> variables = <String, dynamic>{};
variables = {
"objects": [
{"name": name}
],
"onConflict": {
"constraint": "users_pkey",
"update_columns": [
"id",
"name",
]
}
};
await GraphQLUtils()
.queryRepo(UserQueries.userInsertQuery, variables)
.then((response) async {
if (response["data"] != null) {
print("----Data---:${response["data"]}");
Get.back();
} else {
Get.snackbar(
"Error",
"Something Went wrong",
);
}
});
} catch (e, st) {
Get.snackbar(
"Error",
e.toString(),
);
}
}
While i trying refresh my token with interceptors, its always looping. I dont know why. Firstly i want to show my code;
class ApiService {
final Dio _dio = Dio();
final Dio tokenDio = Dio();
int tryCount = 0;
String? accessToken;
String? refreshToken;
final _storage = const FlutterSecureStorage();
ApiService() {
_dio.options.baseUrl = ApiConstants.baseUrl;
tokenDio.options = _dio.options;
_storage.read(key: "token").then((value) => accessToken = value);
_storage.read(key: "refreshToken").then((value) => refreshToken = value);
_dio.interceptors.add(
QueuedInterceptorsWrapper(
onError: (DioError error, ErrorInterceptorHandler handler) async {
if (error.response?.statusCode == 401) {
log("Hata Aldık! ${error.requestOptions.path}");
RequestOptions options = error.response!.requestOptions;
if ("Bearer $accessToken" != options.headers[HttpHeaders.authorizationHeader]) {
log("token farklıydı! $accessToken / ${options.headers[HttpHeaders.authorizationHeader]} ");
options.headers[HttpHeaders.authorizationHeader] = "Bearer $accessToken";
_dio.fetch(options).then(
(value) => handler.resolve(value),
onError: (e) {
log("error on resolve");
handler.reject(e);
},
);
return;
}
_dio
.get("/Auth/RefreshTokenLogin?refreshToken=${Uri.encodeQueryComponent(refreshToken!)}")
.then((response) async {
log("Token Refreshlendi!");
if (response.statusCode == 200) {
final RefreshTokenResponseModel? model = RefreshTokenResponseModel.fromJson(response.data);
_storage.write(key: "token", value: model!.data!.token);
_storage.write(key: "refreshToken", value: model.data!.refreshToken);
refreshToken = model.data!.refreshToken;
accessToken = model.data!.token;
options.headers[HttpHeaders.authorizationHeader] = "Bearer ${model.data!.token}";
tokenDio.options.headers = options.headers;
// await UserSecureStorage.setField("token", model!.data!.token);
// await UserSecureStorage.setField("refreshToken", model.data!.refreshToken);
// final AuthService _authService = AuthService();
// await _authService.registerDevice();
if (model.data != null && model.data!.contractsToBeApproved!.isNotEmpty) {
final AuthController authController = Get.Get.find();
authController.contractsToBeApproved.value = model.data!.contractsToBeApproved!;
}
_dio.fetch(options).then(
(value) => handler.resolve(value),
onError: (e) {
handler.reject(e);
},
);
return;
}
return;
});
}
return handler.next(error);
},
onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
log("istek atıldı. ${options.path}");
if (accessToken == null) {
_storage.read(key: "token").then((value) {
log("storage readed $value");
accessToken = value;
options.headers[HttpHeaders.authorizationHeader] = "Bearer $value";
tokenDio.options.headers = options.headers;
handler.next(options);
});
} else {
options.headers[HttpHeaders.authorizationHeader] = "Bearer $accessToken";
return handler.next(options);
}
},
),
);
}
Its my ApiService. And my goal is refreshing token. It might have multiple request in same time so I used "QueuedInterceptorsWrapper". After token expire, Its entering to error handler function and logging "Token Refreslendi" after token refresh api call.But after that if i click something for api call its looping infinitely. Whats wrong with my code ? Thanks for help :)
So, i'm trying to download a image with the url, i've tried the image_downloader package example code and it didn't show any error. The issue that i'm having is that the image isn't downloading but on the debug console doesn't say anything.
Future<void> _downloadImage(
String url, {
AndroidDestinationType? destination,
bool whenError = false,
String? outputMimeType,
}) async {
String? fileName;
String? path;
int? size;
String? mimeType;
try {
String? imageId;
if (whenError) {
imageId = await ImageDownloader.downloadImage(url,
outputMimeType: outputMimeType)
.catchError((error) {
if (error is PlatformException) {
String? path = "";
if (error.code == "404") {
print("Not Found Error.");
} else if (error.code == "unsupported_file") {
print("UnSupported FIle Error.");
path = error.details["unsupported_file_path"];
}
setState(() {
_message = error.toString();
_path = path ?? '';
});
}
print(error);
}).timeout(Duration(seconds: 10), onTimeout: () {
print("timeout");
return;
});
} else {
if (destination == null) {
imageId = await ImageDownloader.downloadImage(
url,
outputMimeType: outputMimeType,
);
} else {
imageId = await ImageDownloader.downloadImage(
url,
destination: destination,
outputMimeType: outputMimeType,
);
}
}
if (imageId == null) {
return;
}
fileName = await ImageDownloader.findName(imageId);
path = await ImageDownloader.findPath(imageId);
size = await ImageDownloader.findByteSize(imageId);
mimeType = await ImageDownloader.findMimeType(imageId);
} on PlatformException catch (error) {
setState(() {
_message = error.message ?? '';
});
return;
}
if (!mounted) return;
setState(
() {
var location = Platform.isAndroid ? "Directory" : "Photo Library";
_message = 'Saved as "$fileName" in $location.\n';
_size = 'size: $size';
_mimeType = 'mimeType: $mimeType';
_path = path ?? '';
if (!_mimeType.contains("video")) {
_imageFile = File(path!);
}
return;
},
);
}
and i'm calling it like this
and it shows this in the console
this is the package
https://pub.dev/packages/image_downloader/example
Images doesn't show in gallery
Check above link , it may helpful to you.
You may find Image_gallery_saver too for downloading your image , And if still you go with existing package then you raise a issue with it.
Given lat and long.
Is there any fast/smart way to open maps google/apple in Flutter and head to directions ?
I'm using url_launcher for telephone calls, can i use the plugin to open link that open maps ?
_launchURL() async {
const url = 'https://www.google.com/maps/place/Al+qi,+ADoqi,+Giza+Governorate/#33.0523046,38.2009323,17z/data=!3m1!4b1!4m5!3m4!1s0x1458413a996ec217:0x2411f6b62d93ccc!8m2!3d30.05237!4d31.2031598';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
Yes you can do that using the url_launcher plugin. The following code will open Google Maps when the app is installed on the phone (otherwise it will open the browser):
void _launchMapsUrl(double lat, double lon) async {
final url = 'https://www.google.com/maps/search/?api=1&query=$lat,$lon';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
I created a plugin Map Launcher for that.
To find installed maps on a device you can use:
import 'package:map_launcher/map_launcher.dart';
final availableMaps = await MapLauncher.installedMaps;
And then launch by calling showMarker on it
await availableMaps.first.showMarker(
coords: Coords(31.233568, 121.505504),
title: "Shanghai Tower",
description: "Asia's tallest building",
);
Or just check if map available and launch it if so
if (await MapLauncher.isMapAvailable(MapType.google)) {
await MapLauncher.launchMap(
mapType: MapType.google,
coords: coords,
title: title,
description: description,
);
}
This solution will work on both Android and iOS platforms.
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart';
import 'package:url_launcher/url_launcher.dart';
class MapsLauncher {
static String createQueryUrl(String query) {
var uri;
if (kIsWeb) {
uri = Uri.https(
'www.google.com', '/maps/search/', {'api': '1', 'query': query});
} else if (Platform.isAndroid) {
uri = Uri(scheme: 'geo', host: '0,0', queryParameters: {'q': query});
} else if (Platform.isIOS) {
uri = Uri.https('maps.apple.com', '/', {'q': query});
} else {
uri = Uri.https(
'www.google.com', '/maps/search/', {'api': '1', 'query': query});
}
return uri.toString();
}
static String createCoordinatesUrl(double latitude, double longitude,
[String? label]) {
var uri;
if (kIsWeb) {
uri = Uri.https('www.google.com', '/maps/search/',
{'api': '1', 'query': '$latitude,$longitude'});
} else if (Platform.isAndroid) {
var query = '$latitude,$longitude';
if (label != null) query += '($label)';
uri = Uri(scheme: 'geo', host: '0,0', queryParameters: {'q': query});
} else if (Platform.isIOS) {
var params = {'ll': '$latitude,$longitude'};
if (label != null) params['q'] = label;
uri = Uri.https('maps.apple.com', '/', params);
} else {
uri = Uri.https('www.google.com', '/maps/search/',
{'api': '1', 'query': '$latitude,$longitude'});
}
return uri.toString();
}
static Future<bool> launchQuery(String query) {
return launch(createQueryUrl(query));
}
static Future<bool> launchCoordinates(double latitude, double longitude,
[String? label]) {
return launch(createCoordinatesUrl(latitude, longitude, label));
}
}
Call it like this:
MapsLauncher.launchCoordinates(
37.4220041, -122.0862462, "address");
If you want to use address instead of lat, long, you can use the following.
Referencing https://developers.google.com/maps/documentation/urls/ios-urlscheme, daddr Sets the end point for directions searches
final url = 'comgooglemaps://?daddr=${Uri.encodeFull(address)}&directionsmode=driving';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
and don't forget to add to Info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>comgooglemaps</string>
</array>
I used for this native method
try {
await platform.invokeMethod('showLocation', [event.location[0], event.location[1], event.title]);
} on Exception catch (ex) {
print('${ex.toString()}');
ex.toString();
}
And in android package
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "showLocation") {
val args = (call.arguments) as List<Any>
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("geo:${args[0]}, ${args[1]}?z=23&q=${args[0]},${args[1]}(${args[2]})")))
result.success(null)
} else {
result.notImplemented()
}
}
}
}
2022 solution
void _launchMapsUrl() async {
if (_locationData == null) return;
final url =
'https://www.google.com/maps/search/?api=1&query=${_locationData!.latitude},${_locationData!.longitude}';
Map<String, dynamic>? params = {
'api': '1',
'query': '${_locationData!.latitude},${_locationData!.longitude}'
};
final uri = Uri.https(
'www.google.com',
'/maps/search/',
params,
);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
_showErrorDialog(
errorText:
'Could not launch.\nCheck please if you have Google Maps Application on your device.');
throw 'Could not launch $url';
}
}
I have developped an ibm mobile first application with adapter authorization and challenged handler.I have added an android environment and want to test it against production server, so I deployed the apk on my dev tablet.
I've seen that when trying to invoke a remote adapater worklight tries to get ClientInstanceId by executing a cordova method "WLAuthorizationManagerPlugingetClientInstanceIdHeader". This request results always in a timeout and I can see in console one new entru: "Uncaught (in promise) adapter-communication-error". The method exits with "WL.Logger.debug('Client registration failed with error: ' + JSON.stringify(error));"
Edited: Login flow:
Login implementation:
import {UserModel} from 'app-user';
import {UserService} from 'app-user-service';
import {AppSettingsService} from 'app-settings';
import {AppMasterDataService} from "../master-data/app-master-data-service";
import jsSha from 'js-sha';
import {UserRepository} from "user-repository";
import {NetworkInformation} from ../../infrastructure/phonegap/plugins/network-information';
export class LoggedInUser{
public static inject = [UserService, AppSettingsService, AppMasterDataService, UserRepository];
public info: UserModel;
public isLoggedIn: boolean;
private singleStepAuthRealmChallengeHandler: any;
private _getUserInfoPromise: Promise<UserModel>;
private _listeners: Array<(success: boolean, error: string) => void> = [];
private lastCredentials: any;
constructor(private _userService: UserService, private _settingsService: AppSettingsService, private _masterDataService: AppMasterDataService, private _userRepo: UserRepository){
if(typeof WL != "undefined"){
this.singleStepAuthRealmChallengeHandler = WL.Client.createChallengeHandler('GicarAuthRealm');
this.singleStepAuthRealmChallengeHandler.isCustomResponse = this.isCustomResponse.bind(this);
this.singleStepAuthRealmChallengeHandler.handleChallenge = this.handleChallenge.bind(this);
}
}
public async initializeUserInfo(): Promise<void>{
return this.executeLogOut(null, null);
}
public addLoginEventListener(callback: (success: boolean, error: string) => void){
if(!this._listeners.some(x => x === callback)){
this._listeners.push(callback);
}
}
public removeLoginEventListener(callback: (success: boolean, error: string) => void){
let index = this._listeners.indexOf(callback);
if(index >= 0){
this._listeners.splice(index, 1);
}
}
private raiseLoginEvent(success: boolean, error?: string){
for (var listener of this._listeners){
try {
listener(success, error);
}catch (e){
this.removeLoginEventListener(listener);
}
}
}
public prepareLogin(){
if(NetworkInformation.connected())
this._getUserInfoPromise = this._userService.getUserInfo();
}
public async executeLogIn(userName: string, password: string){//: Promise<boolean>{
await this.executeLogOut(userName, password);
if(this.singleStepAuthRealmChallengeHandler){
if(NetworkInformation.connected()){
var userNameSha = new jsSha("SHA-512", "TEXT");
userNameSha.update(userName);
var userNameHash = userNameSha.getHash("B64");
var passwordSha = new jsSha("SHA-512", "TEXT");
passwordSha.update(password);
var passwordHash = passwordSha.getHash("B64");
this.lastCredentials = {
userName: userNameHash,
password: passwordHash
};
var invocationData = {
adapter : "GicarAuthAdapter",
procedure : "submitAuthentication",
parameters : [ userName, window.btoa(userName + ':' + password) ]
};
this.singleStepAuthRealmChallengeHandler.submitAdapterAuthentication(invocationData);
}else {
this.doDisconnectedLogin(userName, password);
}
}
else{
this._userService.logIn(userName, password)
.then(info =>{
this.info = info;
this.isLoggedIn = typeof info !== 'undefined' && info != null;
this.raiseLoginEvent(this.isLoggedIn);
}).catch(e =>{
this.isLoggedIn = false;
this.info = null;
this.raiseLoginEvent(false, e.message ? e.message : e.toString())
});
}
}
private async doDisconnectedLogin(userName: string, password: string){
var userNameSha = new jsSha("SHA-512", "TEXT");
userNameSha.update(userName);
var userNameHash = userNameSha.getHash("B64");
var passwordSha = new jsSha("SHA-512", "TEXT");
passwordSha.update(password);
var passwordHash = passwordSha.getHash("B64");
var persisted = await this._userRepo.findUserByUserName(userNameHash);
let success = persisted && persisted.password == passwordHash;
this.info = persisted;
this.isLoggedIn = success;
this.raiseLoginEvent(success, success ? null : 'user-invalid-credentials');
}
public executeLogOut(userName: string, password: string): Promise<void>{
this.lastCredentials = null;
if(NetworkInformation.connected()){
return this._userService.logOut(this.info).then(() =>{
this.isLoggedIn = false;
this.info = null;
});
}
else
return Promise.resolve();
}
private isCustomResponse(response: any): boolean{
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
if (typeof(response.responseJSON.authRequired) !== 'undefined'){
return true;
} else {
return false;
}
}
private async handleChallenge(response: JQueryXHR){
var authRequired = response.responseJSON.authRequired;
if(authRequired == true){
this.info == null;
this.raiseLoginEvent(false, response.responseJSON.errorMessage);
}else {
try {
if(this.info == null){
this.singleStepAuthRealmChallengeHandler.submitSuccess();
this.info = await this._getUserInfoPromise;
await this._masterDataService.initializeMasterData(false);
if(this.lastCredentials){
await this._userRepo.saveUser({
entityId: this.lastCredentials.userName,
firstName: this.info.firstName,
lastName: this.info.lastName,
fullName: this.info.fullName,
email: this.info.email,
nif: this.info.nif,
address: this.info.address,
userName: this.lastCredentials.userName,
password: this.lastCredentials.password
});
}
this.isLoggedIn = true;
this.raiseLoginEvent(true);
}
}catch (error){
this.raiseLoginEvent(false, error.message ? error.message : error.toString());
}
}
}
}
I think I found the issue.
In order to support several environment, including desktopbrowser's one, I'm calling MFP adapter using the "old" method:`
WL.Client.invokeProcedure({
adapter: "UserServiceAdapter",
procedure: 'getUserInfo'
parameters: [],
compressResponse: false
},{
timeout:30000,
onSuccess: handleSuccess,
onFailure: handleFailure
});
If I replace above code by:
var resourceRequest = new WLResourceRequest("/adapters/UserServiceAdapter/getUserInfo", WLResourceRequest.GET, 30000);
resourceRequest.send().then(
handleSuccess,
handleFailure
);
It's working fine on Android.
It seems I have to check the environment in order to decide the adapter invocation method