I am trying to make a request to the Google Directions API with multiple waypoints. Everything works fine so far, but the main problem that I'm having is that when the Google Maps app is open for the user, all that the user can see are the coordinates.
I am working on a Flutter App, but probably this request is the same for all devices and platforms, so it's not really Flutter-specific.
I want to show the name of the companies/places on the route.
It could be either a web request or a request using the URL scheme for the Google Maps mobile app.
This is what I'm doing so far, with the coordinates.
Future<void> launchGoogleMaps(BuildContext context) async {
Position userLocation = await Geolocator().getLastKnownPosition(
desiredAccuracy: LocationAccuracy.bestForNavigation,
);
String googleMapsAppUrl = 'comgooglemapsurl://?';
if (customFirstPlace != null) {
googleMapsAppUrl +=
"saddr=${customFirstPlace.latitude},${customFirstPlace.longitude}";
} else if (!shouldStartWithUserLocation) {
googleMapsAppUrl +=
"saddr=${circuitCompanies[0].lat},${circuitCompanies[0].lng}";
}
String googleMapsWebUrl = "http://www.google.com/maps/dir";
googleMapsWebUrl += "/${userLocation.latitude},${userLocation.longitude}";
circuitCompanies.forEach((CompanyModel element) {
int elementIndex = circuitCompanies.indexOf(element);
// If it's the first element, the "direction"
// parameter will be added to specify the beginning.
// If not, the "to" parameter will be added
// to specify a waypoint (a stop).
if (elementIndex == 0) {
googleMapsAppUrl += "&daddr=${element.lat},${element.lng}";
} else {
googleMapsAppUrl += "+to:${element.lat},${element.lng}";
}
googleMapsWebUrl += "/${element.lat},${element.lng}";
});
if (await canLaunch("comgooglemaps://")) {
print('launching com googleUrl $googleMapsAppUrl');
await launch(googleMapsAppUrl);
} else if (await canLaunch(googleMapsWebUrl)) {
print('launching web url $googleMapsWebUrl');
await launch(googleMapsWebUrl);
} else {
showDialog(
builder: (_) {
return SingleActionDialog(
title: "Erreur",
onConfirmTap: () => Navigator.pop(context),
bodyText: "Un erreur s'est produit.",
confirmText: "Fermer",
);
},
context: context,
);
}
}
How could I show the appropriate route, with the name of the places that the user will go, instead of only showing the coordinates? I have access to the precise place address as well.
Thanks!
I managed to solve this issue. I instead used the web URL provided by the Google Maps API.
I made a function that returns the address of the place following the Google Maps standard, instead of just passing coordinates.
Future<String> getEncodedCompanyAddress(CompanyModel model) async {
String _encodedAddress = "";
model.address = await CompanyAddressDAO().getCompanyAddress(
model.id,
);
_encodedAddress = model.details.title +
", " +
model.address.street +
", " +
model.address.city +
", " +
model.address.state;
_encodedAddress = Uri.encodeFull(_encodedAddress);
_encodedAddress = _encodedAddress.replaceAll("%20", "+");
return _encodedAddress;
}
Now, instead of showing only the coordinates, the actual place name is shown in the directions of the Google Maps app.
Related
This question already has an answer here:
How can I resize all existing images in firebase storage?
(1 answer)
Closed 9 months ago.
I have requirement to resize new and existing images stored in firebase store. For new image, I enabled firebase's resize image extension. For existing image, how can I resized the image and get the newly resized image url to update back to database via api.
Here is my firebase function to get existing image urls from database. My question is how to resize the image and get the new image url?
const functions = require("firebase-functions");
const axios =require("axios");
async function getAlbums() {
const endpoint = "https://api.mydomain.com/graphql";
const headers = {
"content-type": "application/json",
};
const graphqlQuery = {
"query": `query Albums {
albums {
id
album_cover
}
}`
};
functions.logger.info("Call API");
const response = await axios({
url: endpoint,
method: 'post',
headers: headers,
data: graphqlQuery
});
if(response.errors) {
functions.logger.info("API ERROR : ", response.errors) // errors if any
} else {
return response.data.data.albums;
}
}
exports.manualGenerateResizedImage = functions.https.onRequest(async () => {
const albums = await getAlbums();
functions.logger.info("No. of Album : ", albums.length);
});
I think the below answer from Renaud Tarnec will definitely help you.
If you look at the code of the "Resize Images" extension, you will see that the Cloud Function that underlies the extension is triggered by a onFinalize event, which means:
When a new object (or a new generation of an existing object) is
successfully created in the bucket. This includes copying or rewriting
an existing object.
So, without rewriting/regenerating the existing images the Extension will not be triggered.
However, you could easily write your own Cloud Function that does the same thing but is triggered, for example, by a call to a specific URL (HTTPS cloud Function) or by creating a new document in a temporary Firestore Collection (background triggered CF).
This Cloud Function would execute the following steps:
Get all the files of your bucket, see the getFiles() method of the
Google Cloud Storage Node.js Client API. This method returns a
GetFilesResponse object which is an Array of File instances.
By looping over the array, for each file, check if the file has a
corresponding resized image in the bucket (depending on the way you
configured the Extension, the resized images may be in a specific
folder)
If a file does not have a corresponding resized image, execute the
same business logic of the Extension Cloud Function for this File.
There is an official Cloud Function sample which shows how to create a Cloud Storage triggered Firebase Function that will create resized thumbnails from uploaded images and upload them to the database URL, (see the last lines of index.js file)
Note : If you have a lot of files to treat, you should most probably work by batch, since there is a limit of 9 minutes for Cloud Function execution. Also, depending on the number of images to treat, you may need to increase the timeout value and/or the allocated memory of your Cloud Function, see https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation
In case someone need it. This is how I resized existing image.
const functions = require("firebase-functions");
const axios = require("axios");
const { Storage } = require("#google-cloud/storage");
const storage = new Storage();
// Don't forget to replace with your bucket name
const bucket = storage.bucket("projectid.appspot.com");
async function getAlbums() {
const endpoint = "https://api.mydomain.com/graphql";
const headers = {
"content-type": "application/json",
};
const graphqlQuery = {
query: `query Albums {
albums {
id
album_cover
}
}`,
};
const response = await axios({
url: endpoint,
method: "post",
headers: headers,
data: graphqlQuery,
});
if (response.errors) {
functions.logger.error("API ERROR : ", response.errors); // errors
if any
} else {
return response.data.data.albums;
}
}
function getFileName(url) {
var decodeURI = decodeURIComponent(url);
var index = decodeURI.lastIndexOf("/") + 1;
var filenameWithParam = decodeURI.substr(index);
index = filenameWithParam.lastIndexOf("?");
var filename = filenameWithParam.substr(0, index);
return filename;
}
function getFileNameFromFirestore(url) {
var index = url.lastIndexOf("/") + 1;
var filename = url.substr(index);
return filename;
}
const triggerBucketEvent = async () => {
bucket.getFiles(
{
prefix: "images/albums", // you can add a path prefix
autoPaginate: false,
},
async (err, files) => {
if (err) {
functions.logger.error(err);
return;
}
const albums = await getAlbums();
await Promise.all(
files.map((file) => {
var fileName = getFileNameFromFirestore(file.name);
var result = albums.find((obj) => {
return getFileName(obj.album_cover) === fileName;
});
if (result) {
var file_ext = fileName.substr(
(Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1
);
var newFileName = result.id + "." + file_ext;
// Copy each file on thumbs directory with the different name
file.copy("images/albums/" + newFileName);
} else {
functions.logger.info(file.name, " not found in album list!");
}
})
);
}
);
};
exports.manualGenerateResizedImage = functions.https.onRequest(async () => {
await triggerBucketEvent();
});
Im using geocode api from google maps and Im trying to use the answer from server to fill up a form, the problem is, it's not a pattern of object, the result[0].address_components sometimes return 4, 5 and 7 obj and I can`t to know with one is the city, country etc, there is some way to get like result.something.street, result.something.city etc?
else{
Geocode.fromAddress(cep).then(
response => {
const { lat, lng } = response.results[0].geometry.location;
console.log(response.results[0].address_components);
console.log(response);
},
error => {
console.error(error);
}
);
}
You need to filter the object
Working Fiddle
function getValue(adress_components, component_name) {
return adress_components.filter(c => c.types[0] == component_name)[0].long_name
}
var components = response.results[0].address_components;
console.log(getValue(components, 'street_number'));
console.log(getValue(components, 'locality'));
console.log(getValue(components, 'country'));
console.log(getValue(components, 'postal_code'));
I'm trying to detect whether Google Maps app is installed on iOS, and if so, launch it, if not, launch Apple Maps. Here is what I have so far, but on my phone with Google Maps installed, it isn't detecting it and launching appropriately.
Any ideas?
import 'package:url_launcher/url_launcher.dart';
_launchMaps() async {
String googleUrl =
'comgooglemaps://?center=${trip.origLocationObj.lat},${trip.origLocationObj.lon}';
String appleUrl =
'https://maps.apple.com/?sll=${trip.origLocationObj.lat},${trip.origLocationObj.lon}';
if (await canLaunch("comgooglemaps://")) {
print('launching com googleUrl');
await launch(googleUrl);
} else if (await canLaunch(appleUrl)) {
print('launching apple url');
await launch(appleUrl);
} else {
throw 'Could not launch url';
}
}
I pulled the url scheme from here: How would I be able to open google maps when I press a button in my app?
you can install the packege url_launcher and use the code down below:
import 'package:url_launcher/url_launcher.dart';
class MapUtils {
MapUtils._();
static Future<void> openMap(double latitude, double longitude) async {
String googleUrl = 'https://www.google.com/maps/search/?api=1&query=$latitude,$longitude';
if (await canLaunch(googleUrl)) {
await launch(googleUrl);
} else {
throw 'Could not open the map.';
}
}
}
Now you can open google maps in your app just call this method:
MapUtils.openMap(-3.823216,-38.481700);
I found my issue: this needs to be in the plist file. The code in the question above is fine. (The SO answer referenced in the question only mentioned the "comgooglemaps" string.)
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlechromes</string>
<string>comgooglemaps</string>
</array>
Docs: https://developers.google.com/maps/documentation/ios-sdk/start#step_7_declare_the_url_schemes_used_by_the_api
Do it this way
Full code is given below
static void navigateTo(double lat, double lng) async {
var uri = Uri.parse("google.navigation:q=$lat,$lng&mode=d");
if (await canLaunch(uri.toString())) {
await launch(uri.toString());
} else {
throw 'Could not launch ${uri.toString()}';
}
}
1) in pubspec.yaml
dependencies:
flutter:
sdk: flutter
...
url_launcher: ^5.7.8
2) Import wherever you want to use
import 'package:url_launcher/url_launcher.dart';
3) final you call
onPressed: () {
navigateTo(location.lat, location.lng);
},
If you don't have the actual latlong, you can simply pass an address to Google Maps.
void launchMap(String address) async {
String query = Uri.encodeComponent(address);
String googleUrl = "https://www.google.com/maps/search/?api=1&query=$query";
if (await canLaunch(googleUrl)) {
await launch(googleUrl);
}
}
Of course, the more information you have in the address, the more accurate the search will be. Exactly the same as looking for something on the actual Google Maps page or app.
By the way, you need to url-encode the address before adding it to the URL, to support special characters like spaces. It's only needed for iOS, but hey, we want to develop for all environments out there.
using url launcher
in yaml file: url_launcher: ^5.0.2 last
then you can use this method to open google maps centered to the provided lat and long
more info to maps intent from docs [here][2]
launchMap({String lat = "47.6", String long = "-122.3"}) async{
var mapSchema = 'geo:$lat,$long';
if (await canLaunch(mapSchema)) {
await launch(mapSchema);
} else {
throw 'Could not launch $mapSchema';
}
}
If you want to navigate with directions you can just create a url with source and destination co-ordinates and other coordinates to add as stops.
Steps:
Install url_launcher plugin
write a code like below.
_launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
const url ='https://www.google.com/maps/dir/?api=1&origin=43.7967876,-79.5331616&destination=43.5184049,-79.8473993&waypoints=43.1941283,-79.59179|43.7991083,-79.5339667|43.8387033,-79.3453417|43.836424,-79.3024487&travelmode=driving&dir_action=navigate';
_launchURL(url);
static Future<void> openMap(BuildContext context, double lat, double lng) async {
String url = '';
String urlAppleMaps = '';
if (Platform.isAndroid) {
url = 'https://www.google.com/maps/search/?api=1&query=$lat,$lng';
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
} else {
throw 'Could not launch $url';
}
} else {
urlAppleMaps = 'https://maps.apple.com/?q=$lat,$lng';
url = 'comgooglemaps://?saddr=&daddr=$lat,$lng&directionsmode=driving';
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
} else if (await canLaunchUrl(Uri.parse(urlAppleMaps))) {
await launchUrl(Uri.parse(urlAppleMaps));
} else {
throw 'Could not launch $url';
}
}
}
import 'package:url_launcher/url_launcher.dart';
static void launchMapsUrl(
sourceLatitude,
sourceLongitude,
destinationLatitude,
destinationLongitude) async {
String mapOptions = [
'saddr=$sourceLatitude,$sourceLongitude',
'daddr=$destinationLatitude,$destinationLongitude',
'dir_action=navigate'
].join('&');
final url = 'https://www.google.com/maps?$mapOptions';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
} }
Here you can use this function directly and pass the required parameters and also import this package https://pub.dev/packages/url_launcher/
As follow-up to Roc Boronat's post, the following code can be used for launching the platform specific map application.
Future<void> launchMapUrl(String address) async {
String encodedAddress = Uri.encodeComponent(address);
String googleMapUrl = "https://www.google.com/maps/search/?api=1&query=$encodedAddress";
String appleMapUrl = "http://maps.apple.com/?q=$encodedAddress";
if (Platform.isAndroid) {
try {
if (await canLaunch(googleMapUrl)) {
await launch(googleMapUrl);
}
} catch (error) {
throw("Cannot launch Google map");
}
}
if (Platform.isIOS) {
try {
if (await canLaunch(appleMapUrl)) {
await launch(appleMapUrl);
}
} catch (error) {
throw("Cannot launch Apple map");
}
}
For more information regarding the query parameters in Apple Maps URL, please visit this link.
Edit (7th Aug, 2022): This code will work upto version 6.0.20 of the url_launcher plugin. I could not get it to work after this version as I was getting an ERR_UNKNOWN_URL_SCHEME error when trying to launch Google Maps using canLaunchUrl and launchUrl methods using the versions of the plugin above 6.0.20 and 6.0.20. It works only with the deprecated methods (canLaunch and launch). Just a heads up if anyone wants to try this code snippet.
with 'url_launcher 6.1.0' + physical address instead of lat & lon,
void _pushMap(String address) async {
String query = Uri.encodeComponent(address);
String googleUrl = "google.navigation:q=$query";
Uri googleUri = Uri.parse(googleUrl);
if (await canLaunchUrl(googleUri)) {
await launchUrl(googleUri);
}
}
This will send an implicit Intent to open related apps including google maps.
Haven't tested on iOS devices.
tldr: I think there's an error in the library and canLaunch sometimes returns false even if the url can be launched.
I was trying to open a google maps link (https://goo.gl/maps/mHGzrGUhUHrQByAm8) the same way I do for another link from my app, but for whatever reason canLaunch always returned false.
So now I launch in a try catch block to make sure it doesn't crash my app, and it's working.
try {
launch(url);
} catch (error, stack) {
// log error
}
you can install the packege url_launcher and use the code down below:
This is the latest code as per
url_launcher: 6.1.6
canLaunch();
launch(); these methods has been deprecated now.
class GoogleMapUtils {
GoogleMapUtils._();
static Future<void> openMapApp(double latitude, double longitude) async {
Uri googleUrl = Uri.parse('https://www.google.com/maps/search/?api=1&query=$latitude,$longitude');
if (await canLaunchUrl(googleUrl)) {
await launchUrl(googleUrl);
} else {
throw 'Unable open the map.';
}
}
}
Use plugin:
intent: ^1.4.0
Try the following code:
static void navigateTo(double lat, double lng) async {
var uri = Uri.parse("google.navigation:q=$lat,$lng&mode=c");
android_intent.Intent()
..setAction(android_action.Action.ACTION_VIEW)
..setData(uri)
..setPackage("com.google.android.apps.maps")
..startActivity().catchError((e) => print(e));
}
Note: Only works on Android devices
Install url_launcher package
use the below function
void launchMap() async {
Uri googleUrl = Uri.parse('https://www.google.com/maps/search/?api=1&query=Googleplex');
if (await canLaunchUrl(googleUrl)) {
await launchUrl(googleUrl, mode:LaunchMode.externalApplication);
}
}
Using url luncher with navigation open by default.
Sample code - if app installed it will open in app otherwise open in any browser
///launch map
Future<void> openMap(double latitude, double longitude) async {
String mapUrl = '';
if (Platform.isIOS) {
mapUrl =
'https://maps.apple.com/?daddr=$latitude,$longitude';
} else {
mapUrl =
'https://www.google.com/maps/dir/?api=1&destination=$latitude,$longitude&travelmode=driving';
}
if (await canLaunchUrl(Uri.parse(mapUrl))) {
await launchUrl(Uri.parse(mapUrl),mode: LaunchMode.externalApplication);
} else {
throw 'Could not open the map.';
}
}
if you like to open google map in apple devices add this code in info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlechromes</string>
<string>comgooglemaps</string>
</array>
<key>LSApplicationQueriesSchemes</key>
For other queries
Google url params example
https://www.google.com/maps/dir/?api=1
&origin=$latitude,$longitude
&destination=$latitude,$longitude
&travelmode=driving
&dir_action=navigate
Apple
q= query
saddr = starting point for directions
daddr = destination point for directions
dirflg = The transport type
I have a Chrome extension that requests a user to login using the chrome.identity.getAuthToken route. This works fine, but when you login you can only use the users that you have accounts in Chrome for.
The client would like to be able to login with a different Google account; so rather than using the.client#gmail.com, which is the account Chrome is signed in to, they want to be able to login using the.client#company.com, which is also a valid Google account.
It is possible for me to be logged in to Chrome with one account, and Gmail with a second account, and I do not get the option to choose in the extension.
Is this possible?
Instead of authenticating the user using the chrome.identity.getAuthToken , just implement the OAuth part yourself.
You can use libraries to help you, but the last time I tried the most helpful library (the Google API Client) will not work on a Chrome extension.
Check out the Google OpenID Connect documentation for more info. In the end all you have to do is redirect the user to the OAuth URL, use your extension to get Google's answer (the authorization code) and then convert the authorization code to an access token (it's a simple POST call).
Since for a Chrome extension you cannot redirect to a web server, you can use the installed app redirect URI : urn:ietf:wg:oauth:2.0:oob. With this Google will display a page containing the authorization code.
Just use your extension to inject some javascript code in this page to get the authorization code, close the HTML page, perform the POST call to obtain the user's email.
Based on David's answer, I found out that chrome.identity (as well as generic browser.identity) API now provides a chrome.identity.launchWebAuthFlow method which can be used to launch an OAuth workflow. Following is a sample class showing how to use it:
class OAuth {
constructor(clientId) {
this.tokens = [];
this.redirectUrl = chrome.identity.getRedirectURL();
this.clientId = clientId;
this.scopes = [
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.send"
];
this.validationBaseUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo";
}
generateAuthUrl(email) {
const params = {
client_id: this.clientId,
response_type: 'token',
redirect_uri: encodeURIComponent(this.redirectUrl),
scope: encodeURIComponent(this.scopes.join(' ')),
login_hint: email
};
let url = 'https://accounts.google.com/o/oauth2/auth?';
for (const p in params) {
url += `${p}=${params[p]}&`;
}
return url;
}
extractAccessToken(redirectUri) {
let m = redirectUri.match(/[#?](.*)/);
if (!m || m.length < 1)
return null;
let params = new URLSearchParams(m[1].split("#")[0]);
return params.get("access_token");
}
/**
Validate the token contained in redirectURL.
This follows essentially the process here:
https://developers.google.com/identity/protocols/OAuth2UserAgent#tokeninfo-validation
- make a GET request to the validation URL, including the access token
- if the response is 200, and contains an "aud" property, and that property
matches the clientID, then the response is valid
- otherwise it is not valid
Note that the Google page talks about an "audience" property, but in fact
it seems to be "aud".
*/
validate(redirectURL) {
const accessToken = this.extractAccessToken(redirectURL);
if (!accessToken) {
throw "Authorization failure";
}
const validationURL = `${this.validationBaseUrl}?access_token=${accessToken}`;
const validationRequest = new Request(validationURL, {
method: "GET"
});
function checkResponse(response) {
return new Promise((resolve, reject) => {
if (response.status != 200) {
reject("Token validation error");
}
response.json().then((json) => {
if (json.aud && (json.aud === this.clientId)) {
resolve(accessToken);
} else {
reject("Token validation error");
}
});
});
}
return fetch(validationRequest).then(checkResponse.bind(this));
}
/**
Authenticate and authorize using browser.identity.launchWebAuthFlow().
If successful, this resolves with a redirectURL string that contains
an access token.
*/
authorize(email) {
const that = this;
return new Promise((resolve, reject) => {
chrome.identity.launchWebAuthFlow({
interactive: true,
url: that.generateAuthUrl(email)
}, function(responseUrl) {
resolve(responseUrl);
});
});
}
getAccessToken(email) {
if (!this.tokens[email]) {
const token = await this.authorize(email).then(this.validate.bind(this));
this.tokens[email] = token;
}
return this.tokens[email];
}
}
DISCLAIMER: above class is based on open-source sample code from Mozilla Developer Network.
Usage:
const clientId = "YOUR-CLIENT-ID"; // follow link below to see how to get client id
const oauth = new OAuth();
const token = await oauth.getAccessToken("sample#gmail.com");
Of course, you need to handle the expiration of tokens yourself i.e. when you get 401 from Google's API, remove token and try to authorize again.
A complete sample extension using Google's OAuth can be found here.
I'm using NodeJS and an npm package called oauth to communicate with Twitter's search API. For some reason however, twitter is returning to me an empty array of statuses without any error... What is even more confusing is the fact that using a tool like Postman with the exact same request and keys returns the list of tweets? It makes no sense! Here is my request:
URL: https://api.twitter.com/1.1/search/tweets.json?count=100&q=hello&since_id=577103514154893312&max_id=577103544903462913
Here is my code:
var twitter_auth = new OAuth(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
config.consumer_key,
config.consumer_secret,
"1.0A",
null,
"HMAC-SHA1"
);
var request = twitter_auth.get(
"https://api.twitter.com/1.1/search/tweets.json" + url,
config.access_token,
config.access_token_secret
);
var chunk = "", message = "", that = this;
request.on("response", function(response){
response.setEncoding("utf8");
response.on("data", function(data){
chunk += data;
try {
message = JSON.parse(chunk);
} catch(e) {
return;
}
console.log(message);
if(message.statuses)
{
for(var i = 0; i < message.statuses.length; i++)
{
var tweet = message.statuses[i];
that.termData[term.name].push(tweet);
}
if(message.search_metadata.next_results)
{
that.openRequests.push(that.createNewSearch(message.search_metadata.next_results, term));
}
else
{
that.termCompleted(term);
}
}
else if(message)
{
console.log("Response does not appear to be valid.");
}
});
response.on("end", function(){
console.log("Search API End");
});
response.on("error", function(err){
console.log("Search API Error", err);
});
});
request.end();
The console.log(message) is returning this:
{
statuses: [],
search_metadata: {
completed_in: 0.007,
max_id: 577103544903462900,
max_id_str: '577103544903462913',
query: 'hello',
refresh_url: '?since_id=577103544903462913&q=hello&include_entities=1',
count: 100,
since_id: 577103514154893300,
since_id_str: '577103514154893312'
}
}
Any ideas what is going on? Why is the statuses array empty in my code but full of tweets in Postman?
This issue was described at twittercommunity.com.
Accordingly answer of user rchoi(Twitter Staff):
"Regarding web vs. API search, we're aware that the two return different results at the moment. We made upgrades to the web search. There is no timeline for those
changes to be brought to other parts of our system."
Try to use
https://dev.twitter.com/rest/reference/get/statuses/mentions_timeline
https://dev.twitter.com/rest/reference/get/statuses/user_timeline
if you get empty result with api search functionality.
Please follow this link
https://twittercommunity.com/t/search-tweets-api-returned-empty-statuses-result-for-some-queries/12257/6