Android Question Running Javascript in a WebView that is embedded in HTML file

TheWind777

Active Member
Licensed User
Longtime User
I am currently trying to load an html page that will call the FaceBook SDK to be envoked in order to do a LIKE and SHARE.

I turn-on JavaScript on the WebView with a:

B4X:
WebViewURL.JavaScriptEnabled = True

The html file that is being loaded into the Webview looks like this:

B4X:
<html>
<head>

<title>Weblinks</title>

</head>

<body bgcolor=white>

<!-- https://developers.facebook.com/docs/javascript/quickstart/v2.1 -->
<!-- https://developers.facebook.com/docs/plugins/like-button -->

<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=387721248047129&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

<div class="fb-like" data-href="https://www.facebook.com/people/Acim-WowAcim/100008000028793" data-layout="standard" data-action="like" data-show-faces="false" data-

share="true"></div>

<br><br>

<!--- A LIST OF WEB URL LINKS --->

</body>

</html>

The list of web links show and work... but no JavaScript is being run, it would appear (because the LIKE and SHARE buttons are not showing).

...

So, my question is - isn't JavaScript supposed to now be running when the page loads into the WebView?

And, if so, why aren't a LIKE and SHARE button being displayed?

Doesn't setting

B4X:
   WebViewURL.JavaScriptEnabled = True

allow embedded JavaScript in <script> (and other places Javascript should run) to run?
 

TheWind777

Active Member
Licensed User
Longtime User
JS is enabled by default.

Try to change js.src to start with http (or https).

When I'm very far away from a solution things can be frustrating... but when you know that you are just THIS CLOSE to the final solution; grrrr.

I even put a cut-and-paste JavaScript calculator after the code to ensure that the JavaScript interpreter is working properly. Now I can add and multiply numbers... but I still have no LIKE or SHARE button.

I have pared it down to the barest minimum and still nothing (and I don't understand why). It should be displaying a LIKE button.



B4X:
<html>
<head>

<title>Weblinks</title>

</head>

<body>

<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "http://connect.facebook.net/en_US/sdk.js#xfbml=1&appId=387721248047129&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>


<div class="fb-like" data-href="https://www.facebook.com/people/Acim-WowAcim/100008000028793" data-width="200px"

data-layout="standard" data-action="like" data-show-faces="false" data-share="false"></div>

</body>

</html>

That is the code that comes straight out of their

I even tried going to Advanced and turning-on : Embedded browser OAuth Login to YES


It can't get any simpler than that. The webview links work. The JavaScript calculator works. Why doesn't the Facebook LIKE button work?

B4X:
data-href="https://www.facebook.com/people/Acim-WowAcim/100008000028793"

links to the page I want to have them do the LIKE on (at the moment, any way... eventually that will be the PlayStore App link.) I wonder if it doesn't like that link for some reason?

Under 'Status & Review' the Facebook App is set to YES for "Do you want to make this app and all its live features available to the general public?
I have even succeeded in grabbing profile name, first and last... using the App and the Facebook library.

This should be FAR simpler than doing that. LIKE only needs one function from the SDK.

For unknown reasons the SDK just isn't downloading. Is there a way to verify that the SDK is downloading and installing into the WebView via Logs in some way?

... I think the next step should be to create the simplest B4a app that I can that will do a LIKE button and see if that works. Maybe its something that is wrong with the App that's making it happen (not happen).
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
JS is enabled by default.

Try to change js.src to start with http (or https).

So, I created the most simple App I could.

B4X:
Sub Globals 
  DimWebViewLikeAsWebView
End Sub

Sub Activity_Create(FirstTime AsBoolean)

  ' like is just one WebView, full-size
  Activity.LoadLayout("like")
  WebViewLike.JavaScriptEnabled = True

End Sub


Sub Activity_Resume
  Dim TheHTMLName AsString

  TheHTMLName = file:///android_asset/weblinks2.html
  WebViewLike.LoadUrl(TheHTMLName)
End Sub

I have two weblinks.html and weblinks2.html files I can try. I just get rid of the number 2.

Put the two weblinks.html and weblinks2.html files in the files folder and added them to the project.

weblinks.html =

B4X:
<html>
<head>
<title>Weblinks</title>
</head>
<body>

<div id="fb-root"></div>
  <script>
  window.fbAsyncInit = function() {
  FB.init({
  appId  : '387721248047129',
  xfbml  : true,
  version  : 'v2.0'
  });
  };

  (function(d, s, id){
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js";
  fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));
  </script>

<div class="fb-like" data-href="https://www.facebook.com/people/Acim-WowAcim/100008000028793" data-width="200" data-layout="standard" data-action="like" data-show-faces="false" data-share="false"></div>

<br><br>It is properly loading the HTML file. The LIKE button should be above this line.<br><br>

</body>
</html>

weblinks2.html =

B4X:
<html>
<head>
<title>Weblinks</title>
</head>
<body>

<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=387721248047129&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

<div class="fb-like" data-href="http://www.google.com" data-width="200" data-layout="standard" data-action="like"

data-how-faces="false" data-share="false"></div>

<br><br>It is properly loading the HTML file. The LIKE button should be above this line.<br><br>

</body>

</html>

Both are a white panel with the words: It is properly loading the HTML file. The LIKE button should be above this line. in black.

Both, in theory, should work.

I hardwired the LIKE URL to equal google; does the same thing.

Any ideas?
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
JS is enabled by default.

Try to change js.src to start with http (or https).

One thought is that some permission has to be set in the Manifest file in order to allow the SDK to download. Is there some log file that can be looked at which might tell when permissions have been disallowed?

I did some research and does this make sense at all?

"... into the js/facebook-jssdk.js; and added this line:

B4X:
"content_security_policy":"script-src 'self' https://connect.facebook.net; object-src 'self'",

It's not adding a permission to the Manifest file... but sounds like something that might need to be done. Do you know anything about the js/facebook-jssdk.js file, where it might be found, and why this content_security_policy addition might need to be added to it (when Facebook doesn't mention anything about it)? That might only be pertinent if you're using the Chrome Browser, though.
 
Last edited:
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Possibly some things from this Manifest file need to be added...


B4X:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yooiistudios.chris.facebook_like_sample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".facebook.FBLikeActivity"
android:label="@string/title_activity_fblike" >
</activity>
</application>
</manifest>

In particular... these seem to be important. If the SDK is trying to get inside the Android, and it then has to launch itself; it would make sense that the manifest needs to be informed of it to allow it to occur.

B4X:
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name=".facebook.FBLikeActivity"
android:label="@string/title_activity_fblike" >
</activity>
</application>'

How would those be re-written to work with the B4A Manifest file?
 
Last edited:
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
The manifest elements are not relevant in this case as you haven't added any activity to your project.

Maybe facebook tries to fetch the page url and then it fails as it is not a http url.

No, I tried both http and https, as you had suggested.

Funny that absolutely nothing seems to occur. (I forgot to put permissions for INTERNET into that sample; but it still doesn't work even when you do that).

Huh, so the manifest only is applicable if you add an activity other than the Main activity to the project? Never knew that; but there's so much I don't know - the amount I do know can fit in a thimble.

I'll have to undo the B4A filter and see if that tells anything. The thing that is so annoying is... it should work. By theory, it's simple. And the javascript is being interpreted properly because I stuck that JavaScript calculator at the end of the HTML code and it worked just fine.

Hmmm. It has to be something simple. For some reason the SDK isn't being downloaded, or after it is downloaded, it doesn't run. Did you try it, and on yours it also doesn't work?

The other possibility is that my Facebook App might not have the proper permissions set somewhere (although they don't say you have to do anything special. They make it sound like all you have to do is put the right App ID number and their Facebook Like engine automatically spits out the code that is supposed to be correct for the Android App). I wonder if there's a debugger on the App side that might tell why it isn't sending out the SDK to the App (or even that the SDK was sent out properly, therefore proving that Android is somehow fumbling the ball before it hits the Webview)?
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
The manifest elements are not relevant in this case as you haven't added any activity to your project.

Maybe facebook tries to fetch the page url and then it fails as it is not a http url.

Yeah, their own Facebook Like Engine is what spits out that code that has no http in the data line; Wierd.

Also, when you look up people who are trying to do the same thing (use Javascript from Android in a Webview to create the LIKE button via SDK being asynchronously downloaded)... they don't mention that any part of their problems have to do with that // without the http.

They're usually talking about problems with the manifest. That's why I mentioned that it might be something that's missing from the manifest, which isn't allowing Android to give permission to the App to transfer the SDK to the Webview. That's what I thought the manifest did. Doesn't it set permissions (or not set permissions) for the App which then uses those permissions to stop things if the permission isn't there? (which seems to be what is happening with the SDK, which is why I thought it might have to do with a manifest setting.

I would say it is a pretty important thing to get B4A working with Facebook's LIKE and SHARE buttons. It's a Social Networking world and if it doesn't work with LIKE and SHARE, that's a pretty big deficit. Programmers can't get the word out about their App if those don't work and the App can go viral quickly if they do work and people LIKE the App.
 
Last edited:
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
The manifest elements are not relevant in this case as you haven't added any activity to your project.

Maybe facebook tries to fetch the page url and then it fails as it is not a http url.


Hmmm, I might have gotten LIKE / SHARE to work in a WebView; but not by loading a page with the code embedded in it (which is the nicer way).

I went to the Facebook Developer Like page:

https://developers.facebook.com/docs/plugins/like-button

Next, I chose the link I wanted them to LIKE... chose 200 for the size (want it bigger), Layout: standard, Action Type: like, Show Friends Faces: false, Include Share Button: True

Clicked GET CODE and instead of selecting HTML5 (which is the embedded method), I chose URL.

Then, I just copy-and-pasted that code into B4A as a button sub:

B4X:
Sub ButtonSH_Click

  Dim I As Intent
  Link = http://www.Facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.Facebook.com%2Fpeople%2FAcim-WowAcim%2F100008000028793&width=200&layout=standard&action=like&show_faces=False&share=True&height=35
  I.Initialize(I.ACTION_VIEW,Link)
  StartActivity(I)
end sub

When I click that button, it goes to a blank page which only has a LIKE and SHARE button with 'Be the first of your friends to like this'.

When you click on it, the number goes up by one (but the next time you go in the number said 3 and it still said 'Be the first of your friends to like this' which doesn't make much sense).

Now that I look at the subroutine - it makes me wonder how it even knew to use that webview? I had that as the function set for a button and just used it knowing that it spit an HTTP into the webview without remembering why. Now, when I look at it, how does it know to use that webview?

But it works, or at least seems to work. Just not the right way. This way you have to have a button which says LIKE/SHARE, then when you click on it you get the real buttons (but way too small).

Is there some way of telling it to make the default look bigger in the webview window when it loads it? Making the size of the button be 400 instead of 200 did nothing for the size of the buttons, go figure...

I'm wondering whether the reason that worked was... I have the Facebook App installed. Is that true? Did that code, setting up the intent as I did, call up the Facebook App because the link was http://www.facebook.com ? And, if it was an App, is it possible that it wouldn't work if they didn't have the facebook app installed?

Or, is it just automatically loading some browser when I did a StartActivity() on that Intent?

I don't know whether I like, or hate, having something work (or at least kind of work) - but not know why.
 
Last edited:
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
The manifest elements are not relevant in this case as you haven't added any activity to your project.

Maybe facebook tries to fetch the page url and then it fails as it is not a http url.

I suspect that this has something to do with it... although I don't understand what it means quite yet:

"The first hurdle was the fact that the window.fbAsyncInit() method will not fire if the site page does not have the same URL as your Facebook app URL. This restriction will hold even if you use a content script to call the JS from your app URL–it reads the domain of the page the script is run on, not the domain of the script source. So even though we could append the SDK to any page we wanted, it never initiated the FB connection."

I wonder what they're meaning by 'the site page' and 'your facebook app url'.

Do you know what this means?

They have to match, exactly, right up to the http: or https:

Do you know what they mean? If both don't match exactly, window.fbAsyncInit doesn't succeed.

I believe that this might be the answer; I just don't understand what it means.

They're talking about creating a script for Chrome, but I think it might be a clue to why it's not occurring.

In the meantime I'm debugging the window.fbAsyncInit() javascript function and seeing what is happening, step-by-step. That might shed light at where it's stopping.

I'm wondering whether window.fbAsyncInit() is even firing at all. I have no indication, yet, that it is.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
I came across an interesting thing while researching on the problem:

"Most API's now tend to load via // rather than any specific protocol ( Http: or https: ) because // selects the protocol automatically."

Never knew that.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Here's an idea, use WebViewExtras to add a WebChromeClient to your WebView:

B4X:
Sub Globals 
  Dim WebViewLikeAsWebView
End Sub

Sub Activity_Create(FirstTime AsBoolean)

  ' like is just one WebView, full-size
  Activity.LoadLayout("like")
  WebViewLike.JavaScriptEnabled = True

  '  all webview console messages will now be output bto the android log
  Dim WebViewExtras1 As WebViewExtras
  WebViewExtras1.addWebChromeClient(WebViewLike, "")
End Sub


Sub Activity_Resume
  Dim TheHTMLName AsString

  TheHTMLName = file:///android_asset/weblinks2.html
  WebViewLike.LoadUrl(TheHTMLName)
End Sub

Now all webview console messages will be output to the android log - you can view them instead of them being silently discarded.
You might see some useful javascript error messages here.

Next update your javascript function:

PHP:
<script>
(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {
      console.log("Not loading facebook"); 
      return;
  }
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=387721248047129&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>

It'll log a message if the HTML element with an id of 'facebook-jssdk' already exists in the HTML document.
Looks like the script when first executed should create an HTML element with an id of 'facebook-jssdk', if the script tries to execute a second time it will check for the existence of that element and do nothing if the element already exists.

Martin.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Here's an idea, use WebViewExtras to add a WebChromeClient to your WebView:

B4X:
Sub Globals
  Dim WebViewLikeAsWebView
End Sub

Sub Activity_Create(FirstTime AsBoolean)

  ' like is just one WebView, full-size
  Activity.LoadLayout("like")
  WebViewLike.JavaScriptEnabled = True

  '  all webview console messages will now be output bto the android log
  Dim WebViewExtras1 As WebViewExtras
  WebViewExtras1.addWebChromeClient(WebViewLike, "")
End Sub


Sub Activity_Resume
  Dim TheHTMLName AsString

  TheHTMLName = file:///android_asset/weblinks2.html
  WebViewLike.LoadUrl(TheHTMLName)
End Sub

Now all webview console messages will be output to the android log - you can view them instead of them being silently discarded.
You might see some useful javascript error messages here.

Next update your javascript function:

PHP:
<script>
(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {
      console.log("Not loading facebook");
      return;
  }
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=387721248047129&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>

It'll log a message if the HTML element with an id of 'facebook-jssdk' already exists in the HTML document.
Looks like the script when first executed should create an HTML element with an id of 'facebook-jssdk', if the script tries to execute a second time it will check for the existence of that element and do nothing if the element already exists.

Martin.


I already have a WebChromeClient for the WebView because I was using alert() functions to track-down the problem; so great idea. Thanks.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
I noticed that you had a DONATE button in your trailer. I would love to add a DONATE button to my WebView panel that would allow them to instantly give money to me via PayPal if they'd like (non-profit App)... Do you know how to do that?
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Here's an idea, use WebViewExtras to add a WebChromeClient to your WebView:

B4X:
Sub Globals
  Dim WebViewLikeAsWebView
End Sub

Sub Activity_Create(FirstTime AsBoolean)

  ' like is just one WebView, full-size
  Activity.LoadLayout("like")
  WebViewLike.JavaScriptEnabled = True

  '  all webview console messages will now be output bto the android log
  Dim WebViewExtras1 As WebViewExtras
  WebViewExtras1.addWebChromeClient(WebViewLike, "")
End Sub


Sub Activity_Resume
  Dim TheHTMLName AsString

  TheHTMLName = file:///android_asset/weblinks2.html
  WebViewLike.LoadUrl(TheHTMLName)
End Sub

Now all webview console messages will be output to the android log - you can view them instead of them being silently discarded.
You might see some useful javascript error messages here.

Next update your javascript function:

PHP:
<script>
(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {
      console.log("Not loading facebook");
      return;
  }
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=387721248047129&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>

It'll log a message if the HTML element with an id of 'facebook-jssdk' already exists in the HTML document.
Looks like the script when first executed should create an HTML element with an id of 'facebook-jssdk', if the script tries to execute a second time it will check for the existence of that element and do nothing if the element already exists.

Martin.
 
Upvote 0
Top