I am using GCM with my phonegap android app. The problem I am facing is, the app is able to receive the notification if its open in mobile, but not able to receive notification if its closed. I have gone through the java code written is working fine. But its not able to communicate with javascript code written for receiving message
public class GCMIntentService extends GCMBaseIntentService {
public static final String ME="GCMReceiver";
public GCMIntentService() {
super("GCMIntentService");
}
private static final String TAG = "GCMIntentService";
#Override
public void onRegistered(Context context, String regId) {
Log.v(ME + ":onRegistered", "Registration ID arrived!");
Log.v(ME + ":onRegistered", regId);
JSONObject json;
try
{
json = new JSONObject().put("event", "registered");
json.put("regid", regId);
Log.v(ME + ":onRegisterd", json.toString());
// In this case this is the registration ID
GCMPlugin.sendJavascript( json );
}
catch( JSONException e)
{
// No message to the user is sent, JSON failed
Log.e(ME + ":onRegisterd", "JSON exception");
}
}
#Override
public void onUnregistered(Context context, String regId) {
Log.d(TAG, "onUnregistered - regId: " + regId);
}
#Override
protected void onMessage(Context context, Intent intent) {
Log.d(TAG, "onMessage - context: " + context);
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null) {
try
{
Log.v(ME + ":onMessage extras ", extras.getString("message"));
JSONObject json;
json = new JSONObject().put("event", "message");
json.put("message", extras.getString("message"));
json.put("msgcnt", extras.getString("msgcnt"));
Log.v(ME + ":onMessage ", json.toString());
GCMPlugin.sendJavascript( json );
// Send the MESSAGE to the Javascript application
}
catch( JSONException e)
{
Log.e(ME + ":onMessage", "JSON exception");
}
}
}
#Override
public void onError(Context context, String errorId) {
Log.e(TAG, "onError - errorId: " + errorId);
}
}
I think you are using GCMPlugin plugin.There is nowhere written anything how to handle push notifications when the app will go background or being destroyed.In my opinion its better to remove this plugin and use PushPlugin ,otherwise you have to make a drastic change not only to the GCMIntentservice.java but also to the GCMPlugin.java.
Related
I've been following the documentation for the webview2 on microsoft's official website but I have encountered a problem that I am not sure how to fix.
I have added a .NET object using AddHostObjectToScript and it works as long as the function has no parameter. When calling the object function that has a parameter in JS, I keep on getting a "parameter is incorrect" error.
This is how I am calling the host objects in angular app:
result = await window?.chrome?.webview?.hostObjects.bridge.Func("John");
and this is from my WinUI 3.0 app:
[ComVisible(true)]
public class Bridge
{
public string Func(string param)
{
return "Example: " + param;
}
public string Sample()
{
return "Example: ";
}
public BridgeAnotherClass AnotherObject { get; set; } = new BridgeAnotherClass();
// Sample indexed property.
[System.Runtime.CompilerServices.IndexerName("Items")]
public string this[int index]
{
get { return m_dictionary[index]; }
set { m_dictionary[index] = value; }
}
private Dictionary<int, string> m_dictionary = new Dictionary<int, string>();
}
public sealed partial class WebViewPage : Page
{
public WebViewViewModel ViewModel { get; }
public WebViewPage()
{
ViewModel = Ioc.Default.GetService<WebViewViewModel>();
InitializeComponent();
ViewModel.WebViewService.Initialize(webView);
webView.WebMessageReceived += getMsg;
InitializeAsync();
}
async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async();
var interop = webView.CoreWebView2.As<ICoreWebView2Interop>();
interop.AddHostObjectToScript("bridge", new Bridge());
}
WebView2 currently has an issue where the WinRT API's interop interface AddHostObjectToScript doesn't work well with .NET objects. This is a bug in WebView2.
I want to implement a mechanism in a custom webview client (without JavaScript injection) that can block ads. Is a way I can catch ads and replace them with other ads from a trusted source?
Thanks
In your custom WebViewClient, you can override the function shouldInterceptRequest(WebView, WebResourceRequest).
From Android docs:
Notify the host application of a resource request and allow the application to return the data.
So the general idea is to check if the request is coming from an ad URL (plenty of black list filters out there), then return a "fake" resource that isn't the ad.
For a more in depth explanation plus an example, I recommend checking out this blog post.
To implement this, you have two options:
Use Javascript injected code to do this (which you explicitely said, don't want)
In WebView, instead of "http://example.com" load "http://myproxy.com?t=http://example.com" (properly escaped, of course) and setup "myproxy.com" to be a proxy which will fetch the upstream page (given in "t" query parameter, or in any other way) and replace ads with the trusted ones before sending response to the client. This will be pretty complex, though, because ads can be in many forms, they're usually Javascript injected themselves and you'd probably need to rewrite a lot of URL's in the fetched HTML, CSS and JS files etc.
I made a custom WebViewClient like:
public class MyWebViewClient extends WebViewClient {
#Override
public void onPageFinished(WebView view, String url) { }
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.endsWith(".mp4")) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "video/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
return true;
} else if (url.startsWith("tel:") || url.startsWith("sms:") || url.startsWith("smsto:")
|| url.startsWith("mms:") || url.startsWith("mmsto:")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
private Map<String, Boolean> loadedUrls = new HashMap<>();
#SuppressWarnings("deprecation")
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
boolean ad;
if (!loadedUrls.containsKey(url)) {
ad = AdBlocker.isAd(url);
loadedUrls.put(url, ad);
} else {
ad = loadedUrls.get(url);
}
return ad ? AdBlocker.createEmptyResource() :
super.shouldInterceptRequest(view, url);
}
}
And created an AdBlocker class like:
public class AdBlocker {
private static final Set<String> AD_HOSTS = new HashSet<>();
public static boolean isAd(String url) {
try {
return isAdHost(getHost(url));
} catch (MalformedURLException e) {
Log.e("Devangi..", e.toString());
return false;
}
}
private static boolean isAdHost(String host) {
if (TextUtils.isEmpty(host)) {
return false;
}
int index = host.indexOf(".");
return index >= 0 && (AD_HOSTS.contains(host) ||
index + 1 < host.length() && isAdHost(host.substring(index + 1)));
}
public static WebResourceResponse createEmptyResource() {
return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes()));
}
public static String getHost(String url) throws MalformedURLException {
return new URL(url).getHost();
}
}
And use this WebViewClient in your oncreate like:
webview.setWebViewClient(new MyWebViewClient());
so a quick overview of what I'm doing
I am using Android Webview to Render JavaScript and then reading the HTML from the javascript to parse it.
I am currently having trouble with retrieving the HTML from a website called Sport Chek.
Here is the code for my SportChekSearch class:
public class SportChekSearch extends SearchQuery{
public Elements finalDoc;
private ArrayList<Item> processed;
private final Handler uiHandler = new Handler();
public int status = 0;
//This basically is just so that the class knows which Activity we're working with
private Context c;
protected class JSHtmlInterface {
#android.webkit.JavascriptInterface
public void showHTML(String html) {
final String htmlContent = html;
uiHandler.post(
new Runnable() {
#Override
public void run() {
Document doc = Jsoup.parse(htmlContent);
}
}
);
}
}
/**
* Constructor method
* #param context The context taken from the webview (So that the asynctask can show progress)
*/
public SportChekSearch(Context context, String query) {
final Context c = context;
try {
final WebView browser = new WebView(c);
browser.setVisibility(View.INVISIBLE);
browser.setLayerType(View.LAYER_TYPE_NONE, null);
browser.getSettings().setJavaScriptEnabled(true);
browser.getSettings().setBlockNetworkImage(true);
browser.getSettings().setDomStorageEnabled(true);
browser.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
browser.getSettings().setLoadsImagesAutomatically(false);
browser.getSettings().setGeolocationEnabled(false);
browser.getSettings().setSupportZoom(false);
browser.getSettings().setUserAgentString("Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
browser.addJavascriptInterface(new JSHtmlInterface(), "JSBridge");
browser.setWebViewClient(
new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
browser.loadUrl("javascript:window.JSBridge.showHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
}
}
);
browser.loadUrl("https://www.sportchek.ca/search.html#q=" + query.replaceAll(" ", "+") + "&lastVisibleProductNumber=3");
browser.loadUrl(browser.getUrl());
final String link = browser.getUrl();
new fetcher(c).execute(link);
}
catch(Exception e){
e.printStackTrace();
}
//Get the link from the WebView, and save it in a final string so it can be accessed from worker thread
}
/**
* This subclass is a worker thread meaning it does work in the background while the user interface is doing something else
* This is done to prevent "lag".
* To call this class you must write fetcher(Context c).execute(The link you want to connect to)
*
*/
class fetcher extends AsyncTask<String, Void, Elements> {
Context mContext;
ProgressDialog pdialog;
public fetcher(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pdialog = new ProgressDialog(mContext);
pdialog.setTitle(R.string.finding_results);
pdialog.setCancelable(false);
pdialog.show();
}
//This return elements because the postExecute() method needs an Elements object to parse its results
#Override
protected Elements doInBackground(String... strings) {
//You can pass in multiple strings, so this line just says to use the first string
String link = strings[0];
//For Debug Purposes, Do NOT Remove - **Important**
System.out.println("Connecting to: " + link);
try {
doc = Jsoup.connect(link)
.ignoreContentType(true)
.userAgent("Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")
.timeout(10000)
.get();
finalDoc = doc.select("body section.product-grid-wrapper");
System.out.println(finalDoc.toString());
} catch (IOException e) {
e.printStackTrace();
}
return finalDoc;
}
#Override
protected void onPostExecute(Elements result) {
//This line clears the list of info in the Search activity
//I should probably be using a getter method but adapter is a static variable so it shouldn't matter
//parse seperates document into elements
//crunch results formats those elements into item objects
//I am saving the result of this to an ArrayList<Item> called "processed"
processed = crunchResults(result);
//For debug purposes, do NOT remove - **Important**
System.out.println(processed.size() + " results have been crunched by Sport Chek.");
//Adds all of the processed results to the list of info in Search activity
ClothingSearch.adapter.addAll(processed);
//For debug purposes, do NOt remove - **Important
System.out.println("Adapter has been notified by Sport Chek.");
//Closes the progress dialog called pdialog assigned to the AsyncTask
pdialog.dismiss();
ClothingSearch.adapter.notifyDataSetChanged();
SearchQueueHandler.makeRequest(mContext, processed, SearchQueueHandler.CLOTHING_SEARCH);
}
}
public ArrayList<Item> crunchResults(Elements e){
ArrayList<Item> results = new ArrayList<Item>();
try {
for (int i = 0; i < e.size(); i++) {
Element ele = e.get(i);
String link = "https://www.sportchek.ca" + ele.select(" a.product-grid__link").attr("href");
System.out.println("https://www.sportchek.ca" + ele.select(" a.product-grid__link").attr("href"));
String title = ele.select(" span.product-title-text").text();
String pricestring = ele.select(" span.product-price__wrap").text();
price = Double.parseDouble(pricestring.substring(pricestring.lastIndexOf("$")));
System.out.println(pricestring);
//*******************************************
String store = "Sport Chek";
//Adds the formatted item to an ArrayList of items
results.add(new Item(title, store, price, link));
//Prints the object's to String to console
//For debug purposes, do NOT remove - **Important
System.out.println(results.get(i).toString());
}
} catch (Exception a){
a.printStackTrace();
}
return results;
}
public int getStatus(){
return status;
}
}
The two relevant methods are doInBackground in my AsyncTask and the crunchResults method.
Here is the result I get from using Ctrl+Shift+I on the actual website (Desired Result):
But when running the above code and using a println here is the result that I get for the tag section class="product-grid-wrapper" :
<section class="product-grid-wrapper">
<ul data-module-type="SearchProductGrid" class="product-grid__list product-grid__list_quickview">
<!-- #product-grid__item-template -->
</ul>
</section>
Can anyone help me figure out why I am not getting my desired result?
All help is appreciated
EDIT: for this specific search that the println data was collected from, the link was https://www.sportchek.ca/search.html#q=men+coat&lastVisibleProductNumber=3
It looks like what you are actually getting is the actual html sent by the server, and that your 'desired result' is what the DOM looks like after the JavaScript runs.
Your 'actual' is what I see if I use "View Source" in Chrome, while your "desired result" is what I see if I use Chrome's DOM inspector.
On further inspection, I see that you are not actually getting the HTML from the browser, you are (indirectly) using JSoup's Connection object to get the HTML directly. Unfortunately, that's not going to run the Javascript.
Instead, you're going to have to get the HTML from the WebView after the JavaScript runs. For a possible way to do that, see How do I get the web page contents from a WebView?
Then, you give the HTML that you get from that to JSoup with
Jsoup.parse(html);
I'm trying to get response from U2F Token in GWT project using this source code:
public class Test implements EntryPoint {
#Override
public void onModuleLoad() {
Window.alert("Alert 3:"+u2FTest());
}
public static native String u2FTest()/*-{
var respond = {rep: "Clear"};
var RegistrationData = {"challenge":"dG7vN-E440ZnJaKQ7Ynq8AemLHziJfKrBpIBi5OET_0",
"appId":"https://localhost:8443",
"version":"U2F_V2"};
$wnd.u2f.register([RegistrationData], [],
function(data) {if(data.errorCode) {
alert("U2F failed with error: " + data.errorCode);
return;
}
respond.rep=JSON.stringify(data);
alert("Alert 1: "+respond.rep);
});
alert("Alert 2: "+respond.rep);
return respond.rep;
}-*/;
}
for some reasons I get The Alerts like so:
(Alert 2) first with "Clear" result
(Alert 3) with "Clear"
(Alert 1) with Token response
Normally I've to get (Alert 1) with Token response then 2,3. So how can I stop execution until I'll get the token response
Thank you,
Embrace asynchronicity!
public static native void u2FTest(com.google.gwt.core.client.Callback<String, Integer> callback) /*-{
// …
$wnd.u2f.register(regReqs, signReqs, $entry(function(response) {
if (response.errorCode) {
callback.#com.google.gwt.core.client.Callback::onFailure(*)(#java.lang.Integer::valueOf(I)(response.errorCode));
} else {
callback.#com.google.gwt.core.client.Callback::onSuccess(*)(JSON.stringify(response));
}
}));
}*-/;
(don't forget to wrap callbacks in $entry() so that exceptions are routed to the GWT.UnhandledExceptionHandler, if there's one)
I have an console application which starts a WCF service, and I want to access it in an html file using javascript.
Don't want to use web.config because it seems too complicated. and I want to host the service in an addon of an application later. (but if web.config meets my requirement, it is ok to use it too).
Following is the service code:
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080");
using (ServiceHost host = new ServiceHost(typeof(HelloWorldService), baseAddress))
{
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.AddServiceEndpoint(typeof(IHelloWorldService), new BasicHttpBinding(), "bh");
host.AddServiceEndpoint(typeof(IHelloWorldService), new WebHttpBinding(WebHttpSecurityMode.None), "wb");
host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
host.Close();
}
}
}
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
[WebGet(UriTemplate = "/SayHello?name={name}", ResponseFormat = WebMessageFormat.Json)]
string SayHello(string name);
}
public class HelloWorldService : IHelloWorldService
{
public string SayHello(string name)
{
Console.WriteLine("called SayHello");
return string.Format("Hello, {0}", name);
}
}
And I want to access the service using javascript from a single html file, e.g. index.html like this:
jQuery.post("http://localhost:8080/HelloWorldService.svc/wb/SayHello", {name:"kii"}, function(ret){alert(ret);}});
Or like this:
jQuery.get("http://localhost:8080/HelloWorldService.svc/wb/SayHello?name=kii", function(ret){alert(ret);}});
But they don't work.
"POST" method got "404 Not Found"
and
"GET" method got "405 Method Not Allowed"
Any suggestion?
thanks very much~~
here is the modified program for your reference.
class Program {
static void Main(string[] args) {
Uri baseAddress = new Uri("http://localhost:8080");
using (ServiceHost host = new ServiceHost(
typeof(HelloWorldService), baseAddress)) {
host.Description.Behaviors.Add(
new ServiceMetadataBehavior { HttpGetEnabled = true });
host.AddServiceEndpoint(
typeof(IHelloWorldService), new BasicHttpBinding(), "bh");
var webEndPoint = host.AddServiceEndpoint(
typeof(IHelloWorldService),
new WebHttpBinding(WebHttpSecurityMode.None), "wb");
webEndPoint.Behaviors.Add(new WebHttpBehavior());
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
host.Open();
var n = 0;
foreach (var endPoint in host.Description.Endpoints) {
Console.WriteLine("endpoint " + n);
Console.WriteLine(" address: " + endPoint.Address);
Console.WriteLine(" absolute path: " + endPoint.ListenUri.AbsolutePath);
Console.WriteLine(" absolute uri: " + endPoint.ListenUri.AbsoluteUri);
n++;
}
Console.WriteLine();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}
The only actual difference is to add WebHttpBehavior into the web endpoint.
running this program, and open brower to test address localhost:8080/wb/sayhello?name=abc
if the brower returns "abc", that means the web end point is working.
if calling this address by jQuery is still not working, then trouble-shooting on jQuery side.