I am making an android app and doing pretty well atm. What I want is when a user presses a url with variable search parameters attached to it, that the entire url is sent to my app.
The app opens well, but I don't know how to get the search parameters in there as well.
Btw. the app has a webview of the internet page in it, which works fine. I am opening the app itself as well as clicking on the links sent to whatsapp and messenger from within my app.
E.g. the url could be https://www.sendamap.com/index.php?g=100&z=200
Standard the https://www.sendamap.com is opened. I would like the whole url to be passed to the app.
In android studio I am struggling with the following in the MainActivity;
Intent intent = getIntent();
Uri data = intent.getData();
String url = data.toString();
webView.loadUrl(url);
Okay, it works now. It was mainly in my code (duh).
AndroidManifest.xml; "https" is important (besides everything else).
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="www.sendamap.com" />
</intent-filter>
MainActivity.java; "this." was added before "getIntent().getData().
Uri uri = this.getIntent().getData();
if (uri != null) {
url = uri.toString();
}
webView.loadUrl(url);
Related
I'd like to be able to prompt my app to open a link when user clicks on an URL of a given pattern instead of allowing the browser to open it. This could be when the user is on a web page in the browser or in an email client or within a WebView in a freshly-minted app.
For example, click on a YouTube link from anywhere in the phone and you'll be given the chance to open the YouTube app.
How do I achieve this for my own app?
Use an android.intent.action.VIEW of category android.intent.category.BROWSABLE.
From Romain Guy's Photostream app's AndroidManifest.xml,
<activity
android:name=".PhotostreamActivity"
android:label="#string/application_name">
<!-- ... -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"
android:host="flickr.com"
android:pathPrefix="/photos/" />
<data android:scheme="http"
android:host="www.flickr.com"
android:pathPrefix="/photos/" />
</intent-filter>
</activity>
Once inside you're in the activity, you need to look for the action, and then do something with the URL you've been handed. The Intent.getData() method gives you a Uri.
final Intent intent = getIntent();
final String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
final List<String> segments = intent.getData().getPathSegments();
if (segments.size() > 1) {
mUsername = segments.get(1);
}
}
It should be noted, however, that this app is getting a little bit out of date (1.2), so you may find there are better ways of achieving this.
There are some libraries parse parameters from url automatically.
such as
https://github.com/airbnb/DeepLinkDispatch
&&
https://github.com/mzule/ActivityRouter
The later one is wrote by me. Which can parse parameters to given type, not always String.
Example
#Router(value = "main/:id" intExtra = "id")
...
int id = getIntent().getInt("id", 0);
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
setUrlparams(url);
if (url.indexOf("pattern") != -1) {
// do something
return false;
} else {
view.loadUrl(url);
}
return true;
}
}
I've created a WCF service that I'm attempting to use for a cross-domain call (using jQuery and JSONP). I've written the service and when I run it in the Visual Studio debugger and call it from a test page on my local PC it works fine. When I deploy the service to IIS7 on our server, it doesn't work. Looking at it with Fiddler, I see there's a 400 error coming back.
This is my first attempt at creating a WCF service and also my first attempt at JSONP, so it is highly possible I've missed something simple yet important.
I have 2 methods on this service, one really simple one (called GetData) which just takes a string and returns it - I created this one just to test the basic service functionality (i.e. I can just put the URL into a browser and I get some json back) and it works OK.
The other, problematic, one (called GetMatter) takes a couple of parameters, calls another (SOAP) web service to get some data and returns a Stream containing the call to my callback function. This then gets inserted into the calling page which displays the result.
The contract looks like this:
[ServiceContract]
public interface IOracleService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "getData/{value}")]
string GetData(string value);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "getMatter/{matterId}/{callback}")]
Stream GetMatter(string matterId, string callback);
}
The implementation looks like this:
public class OracleService : IOracleService
{
public string GetData(string value)
{
return string.Format("You entered: {0}", value);
}
public Stream GetMatter(string matterId, string callback)
{
//call web service
var serviceResult = <call to web service goes here>;
//serialize data to json
JavaScriptSerializer js = new JavaScriptSerializer();
string jsonResult = js.Serialize(serviceResult.data);
jsonResult = jsonResult.Substring(1, jsonResult.Length - 2);
string result = callback + "(" + jsonResult + ");";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
}
My simple Test.html page looks like this (for the purposes of this test, the js file is just stored on my local Q: drive):
<html>
<head>
<script src="./jquery-2.2.2.min.js" type="text/javascript"></script>
</head>
<body>
<div id="output"></div>
<div id="output2"></div>
<script language="javascript">
var url = "Q:\TestService.js";
var script = document.createElement("script");
script.setAttribute("src", url);
script.setAttribute("type", "text/javascript");
document.body.appendChild(script);
</script>
</body>
</html>
TestService.js is as follows (note that Service.Legal is the namespace that OracleService is defined in, and MyServer is the name of the server that I've deployed the service to. When running in the debugger, MyServer is changed to "localhost:portnumber" and this works OK then)
var url = "http://MyServer/Service.Legal.OracleWebService/OracleService.svc/GetData/1";
url += "?" + new Date().getTime().toString(); //append time to prevent caching
var script = document.createElement("script");
script.setAttribute("src", url);
script.setAttribute("type", "text/javascript");
document.body.appendChild(script);
function ServiceCallback(data) {
console.log("got data: ");
console.dir(data);
var result = data;
var date = new Date(parseInt(result.INVOICE_DATE.substr(6)));
var output = "<ul>";
output += "<li>INVOICE DATE: " + date + "</li>";
output += "<li>TOTAL EXCL GST: " + result.TOTAL_EXCL_GST + "</li>";
output += "<li>FEE ESTIMATE: " + result.FEE_ESTIMATE + "</li>";
output += "</ul>";
$("#output").html(output);
}
Finally, the web.config looks like:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Windows" />
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpBinding" crossDomainScriptAccessEnabled="true">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<client />
<services>
<service name="Service.Legal.OracleWebService.OracleService">
<endpoint address="" binding="webHttpBinding" contract="Service.Legal.OracleWebService.IOracleService" behaviorConfiguration="webBehaviour" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://MyServer/Service.Legal.OracleWebService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
<httpErrors errorMode="Detailed" />
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
</configuration>
As I said above, when I run this service in the Visual Studio debugger, my html page runs the javascript in TestService.js, the javascript calls my service (http://localhost:15021/OracleService.svc/GetMatter/matterId/ServiceCallback) and I end up with the expected data being displayed on the page.
When I change that service url to point at the server (http://MyServer/Service.Legal.OracleWebService/OracleService.svc/GetMatter/matterId/ServiceCallback), I get a blank page and Fiddler shows the request giving error 400.
A basic test of the web service directly in the browser
http://MyServer/Service.Legal.OracleWebService/OracleService.svc/getData/1
does return the expected json data (although obviously IE just asks if I want to open or save "1.json", it doesn't display anything in the browser), so the service itself does appear to be accessible and working OK in IIS. There just seems to be something wrong with my GetMatter function or the way I'm calling it that is preventing it from working on the server.
Hmm OK never mind, I think I was looking at the wrong problem.
The 400 (bad request) error made me think the problem was with the call to my web service. But it seems the problem is actually happening on the server side when my web service tries to call the other web service. When I took out that call to the other web service, my service returned a 200 (success) instead. I'm going to work on the assumption that what I've got (as posted above) is OK, and the issue is something to do with the call to the other web service. Perhaps a firewall issue that is preventing the call going from my server to that server, while allowing it to go from my development machine to the same server.
I can only find old outdated answers for before UWP Win 10. I know how to do it the old ways, but it is giving me problems.
What I have so far is below, note the problem seem to lie in the VB where it isn't doing the element by tag name command like I've been told it should. Change that to inner HTML though, and it will populate the html variable with the full page. So I just can't get the links themselves it seems.
Any help is appreciated! Thanks!
XAML
<Page
x:Class="webviewMessingAround.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:webviewMessingAround"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<WebView x:Name="webview" Source="http://regsho.finra.org/regsho-December.html" DOMContentLoaded="WebView_DOMContentLoaded" />
<Button x:Name="button" HorizontalAlignment="Left" Margin="145,549,0,0" VerticalAlignment="Top">
<Button x:Name="button1" Click="button_Click" Content="Button" Height="58" Width="141"/>
</Button>
</Grid>
</Grid>
</Page>
VB Code
Private Async Sub webview_DOMContentLoaded(sender As WebView, args As WebViewDOMContentLoadedEventArgs) Handles webview.DOMContentLoaded
Dim html = Await webview.InvokeScriptAsync("eval", ({"document.getElementsByTagName('a');"}))
'Debug.WriteLine(html)
End Sub
The InvokeScriptAsync can only return the string result of the script invocation.
Return value
When this method returns, the string result of the script invocation.
So if you want get links form a web page, you need put all the links into a string to return. For a C# example:
string html = await webview.InvokeScriptAsync("eval", new string[] { "[].map.call(document.getElementsByTagName('a'), function(node){ return node.href; }).join('||');" });
System.Diagnostics.Debug.WriteLine(html);
Here I use
[].map.call(document.getElementsByTagName('a'), function(node){ return node.href; }).join('||');
to put all the links into a string. You may need to change this JavaScript code to implement your own.
After this you can split the string into a array like:
var links = html.Split(new[] { "||" }, StringSplitOptions.RemoveEmptyEntries);
Although I used C# for example, but the VB code should be similar.
I'm trying to get pdf.js to work locally on a windows phone app written in Xamarin but I can't understand why if I pass a url without any querystring it works:
url = "Assets/pdfjs/web/viewer.html"
Uri uri = new Uri(url, UriKind.Relative);
PdfWebViewer.Source = uri;
The above displays the pdf.js viewer correctly but with no pdf file of course but if I change the url to:
url = "Assets/pdfjs/web/viewer.html?file=test.pdf"
Uri uri = new Uri(url, UriKind.Relative);
PdfWebViewer.Source = uri;
I just get a page not found. Note the javascript is enabled.
I've added the various web browser events to see if I could spot anything else, and when I call the url without a querystring, it calls the Navigating event followed by the Navigated event but as soon as I specify a querystring, it triggers the Navigating followed by NavigationFailed event but I can't see the error as the exception returned in e.exception is null.
Am I missing something?? Is this not allowed?
Thanks.
UPDATE:
It may not be a problem with Xamarin as I've just tried the same thing in a WP8.1 using the WebBrowser control and I get exactly the same behaviour.
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
WebBrowser.IsScriptEnabled = True
WebBrowser.Source = New Uri("/Html/Viewer.Html?file=1", UriKind.Relative)
End Sub
My Viewer.html is the most basic page you could have:
<html>
<body>
Test
</body>
</html>
Get rid of the query string and the web browser will display Test. Any ideas??
Using the elementtree package in nodejs, I'm trying to verify the existence of a certain xml attribute in an xml file (specifically an android manifest file).
var manifestTxt = fs.readFileSync('AndroidManifest.xml', 'utf-8'),
manifestDoc = new et.ElementTree(et.XML(manifestTxt)),
expected = 'application/activity[#android:name="com.whatever.app"]';
test.ok(manifestDoc.find(expected));
I'm getting the following exception:
node_modules/elementtree/lib/elementpath.js:210
throw new SyntaxError(token, 'Invalid attribute predicate');
^
Error: Invalid attribute predicate
It doesn't seem to like the colon in the attribute name, but without it the search doesn't match. I think I'm handling the namespace wrong -- but can't find the proper way.
Edit Here's the sample xml I'm searching:
<?xml version='1.0' encoding='utf-8'?>
<manifest ... xmlns:android="http://schemas.android.com/apk/res/android">
<application android:debuggable="true" android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:label="#string/app_name" android:name="com.whatever.app">
<intent-filter>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="5" />
</manifest>
In case you don't have the information how to register the namespace and use the associated prefix for it, use:
application/activity
[#*[local-name()=name'
and
namespace-uri() = 'http://schemas.android.com/apk/res/android'
]
=
'com.whatever.app'
]
Simpler expressions that aren't safe in the general case, but may select the wanted node(s) in this specific case:
application/activity[#*[local-name()='name'] = 'com.whatever.app']
or this expression:
application/activity[#*[name()='android:name'] = 'com.whatever.app']
Elementtree expects namespace URIs, not namespace prefixes.
var manifestTxt = fs.readFileSync('AndroidManifest.xml', 'utf-8'),
manifestDoc = new et.ElementTree(et.XML(manifestTxt)),
expected = '//application/activity[#{http://schemas.android.com/apk/res/android}name="com.whatever.app"]';
test.ok( manifestDoc.find(expected) );
See: ElementTree: Working with Qualified Names
Edit The XPath implementation of node-elementtree does not currently seem to have namespace support at all.
Missing that you'd have to do some legwork:
var manifestTxt = fs.readFileSync('AndroidManifest.xml', 'utf-8'),
manifestDoc = new et.ElementTree(et.XML(manifestTxt)),
activities = manifestDoc.findall('//application/activity'), i;
for (i=0; i<activities.length; i++) {
if ( activities[i].attrib['android:name'] === 'com.whatever.app' ) {
test.ok(true);
}
}
The line if ( activities[i].attrib['android:name'] === 'com.whatever.app' ) { is largely a guess.
I don't know how the parser handles namespaced attributes. When in doubt, just dump the whole activities[i].attrib to the console and see what the parser did. Adapt the above code accordingly. I'm afraid that's as close as you will get with that kind of limited XPath support.