I wanted to know the answer to a simple question but i have'nt found a good one
(i've google it for hours :) )
I'm playing with the sl4a with python and i can send events from js to the python script, but the js is not catching the eventPost i put in the code below from python to js.
Anyone knows how is this been done or if there is another way without the registerCallback?
HTML CODE :
<html>
<head>
<script>
var droid = new Android();
function doit(){
droid.makeToast("Text send :=>"+document.getElementById("msg").value);
droid.eventPost("doit",document.getElementById("msg").value);
}
function alert_me(data){
droid.makeToast("All done!");
document.getElementById("msg").value = '';
}
droid.registerCallback("done",alert_me);
</script>
</head>
<body>
<input type="text" name="boton" id="msg" value="" />
<input type="button" name="boton" value="Go!" onclick="javascript:doit()" />
</body>
</html>
PYTHON CODE:
import android,time
if __name__ == '__main__' :
droid = android.Android()
droid.webViewShow("file:///sdcard/sl4a/scripts/sample.html")
while True:
event = droid.eventWait().result
if event["name"] == 'doit':
droid.makeToast("Event catched! %s" % event['data'])
droid.eventPost("done","Done message")
time.sleep(2)
droid.exit()
This is simple to get working, but isn't obvious or well documented.
First you want to get a hook to the Android object inside the webview. Then you can use it to register one or more callbacks. For a simple example, we'll just do one that pops an alert with a message from Python.
var droid = new Android();
droid.registerCallback("echo", function(msg) {
alert(msg.data)
});
In this case, echo is the name of the event type you want this callback to handle. So this will handle 'echo events'. The event names are arbitrary strings, just call them whatever makes sense.
In the Python script that launched the webview, you can now post events to the registered handler whenever you like.
droid.eventPost("echo", "hello world")
The second argument here is the message you want to pass to the JavaScript callback.
Note that although you pass the message back as a string, it arrives in the JavaScript function as an object. That object, we're calling it msg above, has an attribute called data which contains the string you passed from the Python side.
Unfortunately I have never personally been able to get this working, using both registerCallback() and eventWaitFor(). However, if you are still keen on getting this working, I strongly recommend you head on over and download sl4a_r5x – an unofficial but newer and updated release of SL4A. In it is support for using FullScreenUi's based off the same xml code that native Android apps use. With this you can do what you're after and examples can be found on the page.Hopefully this has been helpful and you're still interested in SL4A!
Related
I tried to develop a simple mobile application that connect to a websocket server. I used Phonegap Build to make my Android .apk, here's the html code :
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
<div id="messages"></div>
<script type="text/javascript">
var webSocket =
new WebSocket('ws://192.168.82.1:8080/WebSocket/websocket');
webSocket.onerror = function(event) {
onError(event)
};
webSocket.onopen = function(event) {
onOpen(event)
};
webSocket.onmessage = function(event) {
onMessage(event)
};
function onMessage(event) {
document.getElementById('messages').innerHTML
+= '<h1 align="center"/>' +" "+ event.data;
}
function onOpen(event) {
document.getElementById('messages').innerHTML
+= '<h1 align="center"/>connection established';
}
function onError(event) {
alert(event.data);
}
</script>
</body>
</html>
The code is working fine on my navigator but the message "connection established" doesn't even appear when I use the Android app.
Is there something wrong with this code or does my app need some library ?
PS : I have another code with a button sending a message to the server and receiving a text from it, and of course it's the same problem !
WebSockets are only supported in WebView after Android 4.4. So if you want to use it in older android versions ,you have some choices:
Use a Cordova plugin that provides that functionality. For example, https://github.com/knowledgecode/WebSocket-for-Android (this is just an example, I have never worked with that plugin)
Use something like SockJS or socket.io to provide webSockets when supported and fallback to other technologies when not. Please note that using those technologies requires you to use them also in the server
I put this add action in my spoutnik controller like the REST doc of cakephp :
public function add() {
$this->layout = null;
$this->autoRender = false;
if ($this->Spoutnik->save($this->request->data)) {
$message = array(
'text' => __('Saved'),
'type' => 'success'
);
} else {
$message = array(
'text' => __('Error'),
'type' => 'error'
);
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
I put this JS part in my angularjs app (actually in a other domain than the cakephp site):
<form ng-controller="MessageController" ng-submit="createMessage()">
<legend>Create Message</legend>
<label>Title</label>
<input type="text" id="name" name="name" ng-model="message.name" placeholder="Title">
<label>Message</label>
<input type="text" id="email" name="email" ng-model="message.email" placeholder="ur message here">
<button class="btn btn-primary">Add</button>
</form>
and
function MessageController($scope, $http) {
$scope.message = {};
$scope.createMessage = function() {
$http({
method : 'POST',
url : 'http://www.mycakephpdomain.com/spoutnik/add',
data : $scope.message
})
}
}
Nothing work... i have no errors in chrome console, i'm totally lost :/ I just want to build an android app in angularjs with no java or PHP, and post to my cakephp website. For the moment, i try to post form an other domain (i can't touch apache configuration).
What is wrong in my code ?
Just for the record and debugging purposes:
I did not find the reason to this same problem, but looking the AJAX request done by AngularJS I found that message data from the form was no being sent as regular form data. Instead it was being sent as REQUEST PAYLOAD.
Indeed, the response from the server contained this error just before the JSON response from my view:
Warning (4096): Argument 1 passed to Hash::get() must be of the type
array, null given, called in
/var/www/test/lib/Cake/Network/CakeRequest.php on line 866 and defined
[CORE/Cake/Utility/Hash.php, line 44]
Of course, i checked that there was nothing strange by my side executed, I even tried disabling all security component and allowing AUTH *.
If you set the core.debug in php to 0, the error wont be shown and
everything will be ok, but thats not what you want for your awesome
app.*
I changed query data from $scope.message to just $('form').serialize(), but still no way.
So finally, the only solution I found was to remove the $http.post and replace it by a very know $.ajax() which just did its job as always...
So thats my suggestion, remove the $http.post and user common jQuery.ajax();
There is much confusion among newcomers to AngularJS as to why the $http service shorthand functions ($http.post(), etc.) don’t appear to be swappable with the jQuery equivalents (jQuery.post(), etc.) The difference is in how jQuery and AngularJS serialize and transmit the data. Fundamentally, the problem lies with your server language of choice being unable to understand AngularJS’s transmission natively ... By default, jQuery transmits data using Content-Type: x-www-form-urlencoded and the familiar foo=bar&baz=moe serialization. AngularJS, however, transmits data using Content-Type: application/json and { "foo": "bar", "baz": "moe" } JSON serialization, which unfortunately some Web server languages—notably PHP—do not unserialize natively.
So concretely, your $_POST variable is empty !
To go through this problem there're 2 solutions:
Change the data format in Angular config
Change the way to get the datas with PHP(Deprecated but works)
I haven't invented anything here, just linking...
Hope it'll help.
I have the following setup on my site. It is working fantastically on any standard browser and any normal mobile browser:
Model:
function SearchTerm(data) {
this.Term = ko.observable(data.Term);
this.Stamp = ko.observable(data.Stamp);
}
ViewModel:
function HistoryViewModel() {
//Data
var self = this;
self.searchTerms= ko.observableArray([]);
// Load history from server
$.ajax({
type: "GET",
url: "/api/history/",
data: null,
success: function (msg) {
var terms = $.map(msg, function (item) { return new SearchTerm(item) });
self.searchTerms(terms);
},
error: function (xhr, ajaxOptions, thrownError) {
// Error Handling
}
});
}
View:
<div class="title">
Search History
<div class="closeBtn"></div>
</div>
<div id="historySection">
<ul class="searches" data-bind="foreach: searchTerms">
<li class="historyItem">
<div class="timestamp"><span data-bind="'text': Stamp"></span></div>
<span data-bind="'text': Term"></span>
</li>
</ul>
<a class="loadMore">Load 10 More Searches »</a>
</div>
All of this works perfectly on everything I test, with one major exception: The WebView control for Android. Whenever I run this page there, I get the following exception:
Uncaught Error: Unable to parse bindings.
Message: ReferenceError: Stamp is not defined;
Bindings value: 'text': Stamp at {url}/Scripts/libs/knockout-2.2.1.js:5
I'm at my wit's end. I've tried every possible combination of data-bind syntax (as you can see I've tried the single quotes too, as I'd seen a post related to that at some point). My only guess now is that this might be related to my order of scripts. I do currently reference knockout before I reference jquery - could this be the issue? I hadn't seen this as an issue anywhere else, but at this point, I'm willing to try anything.
Update:
All of my other knockout binding viewModels and bindings are working fine on Android, but none of them occur on page load. So that led me to look at changing the ajax to a method and trying to delay it's calling. So I implemented the following addition to my viewmodel:
//Operations
self.loadRecent = function () {
// Load search history
$.ajax({
type: "GET",
url: "/api/history/",
data: null,
success: function (msg) {
var terms = $.map(msg, function (item) { return new History(item) });
self.history(terms);
},
error: function (xhr, ajaxOptions, thrownError) {
//Error handling
}
});
In my page, here is what the initial binding looks like - it occurs at the bottom of the page:
var history = new HistoryViewModel();
ko.applyBindings(history, $("#historySection")[0]);
//Call page event handlers
$(window).load(function () {
// Load in our search history
history.loadRecent();
});
Unfortunately, same error as before. However, this is where things get really interesting. Even when I comment out the call to the loadRecent operation, I still get the error! To me, this means, for some reason, for this model only, the foreach is still trying to iterate, even though nothing exists. Do my assumptions sound correct? Anyone see anything I'm blatently missing here that would cause this issue? None of my other viewModels and views are having this issue. I have 2 others I'm binding to and they both have foreach's in them and do not seem to experience this issue.
UPDATED 2013.05.20
I updated some of the code throughout to reflect some function/object renaming I did, as I started to worry that something was getting out of sorts with me having a variable named history with a function named history (silly, I know, but I'm desparate).
I also wanted to post an additional finding. I decided to go ahead and try removing the code for loading the history completely from any loading or ready event. Rather, I was able to separate out this data load into a button click. Here is what the button click handler looks like:
$(".menuButton").on("click", "", function () {
history.searchTerms([]);
history.loadRecent();
});
Fun fact when I do this though, in Android-only. I still get an error on load, in the bindings:
Uncaught Error: Unable to parse bindings.
Message: ReferenceError: searchTerms is not defined;
Bindings value: foreach: searchTerms at {url}/Scripts/libs/knockout-2.2.1.js:5
Another interesting tidbit - if I were to remove the html from the view altogether, meaning there are no bindings, yet still leave the code for the SearchTerm model and the HistoryViewModel, I still get an error from the WebView in Android, when the button is clicked:
Uncaught TypeError: Object #<History> has no method 'searchTerms' at {url}:681
Sorry for so much posting, but I'm desperate to figure out what's wrong with this.
maybe webview does some wacky stuff with HTML 5 history api and its resetting it on top of your history view model. have you tried changing the vm name to historyVM or something? i would argue you shouldnt be naming your viewmodels to match things being used by the browser itself (like, dont name your vm 'window' or 'document')
Is there a way to create a serious HTML/CSS/JS project with multiple HTML, CSS, JS files on JSfiddle.net ?
If yes, how to do it ?
I want to create a basic mobile apps based on HTML/CSS/JS, about a dozen of HTML/CSS/JS files. I would like to develop it all on JSfiddle, my favorite Online JavaScript IDE. But JSfiddle.net while a clean way to test projects stays limited to:
1 html file (personal)
1 CSS file (personal)
1 JS file (personal)
several external resources (CSS, JS libs, data) which request you another webhosting.
The official doc suggesting Github hosting for 1HTML/1JS/1CSS/someDataFiles is not satisfying. I wish all on JSFiddle, and more files in my project.
You can do it inside a jsFiddle but there are few limitations, and you are probably not going to be satisfied with it.
You can test only 1 HTML multiple pages template. But in case of jQuery Mobile framework this will be enough, as you can place numerous jQM pages inside a 1 html file.
For example, this is my jsFiddle template when helping to this group: http://jsfiddle.net/Gajotres/yWTG2/
You cant use normal form submitting. Instead you should use ajax to sumbit form data.
In my other answer you can find solutions for ajax form submitting and how to send parameters during the page transition: jQuery Mobile: Sending data from one page to the another
In case you want to communicate with an remote host:
var ajax = {
sendRequest:function(save_data){
$.ajax({url: 'http://localhost/JSONP_Tutorial/json.php',
data: save_data,
async: true,
beforeSend: function() {
// This callback function will trigger before data is sent
$.mobile.showPageLoadingMsg(true); // This will show ajax spinner
},
complete: function() {
// This callback function will trigger on data sent/received complete
$.mobile.hidePageLoadingMsg(); // This will hide ajax spinner
},
success: function (result) {
if(result == "true") {
$.mobile.changePage( "#index", { transition: "slide"} ); // In case result is true change page to Index
} else {
alert('Login unsuccessful, please try again!'); // In case result is false throw an error
}
// This callback function will trigger on successful action
},
error: function (request,error) {
// This callback function will trigger on unsuccessful action
alert('Network error has occurred please try again!');
}
});
}
}
jsFiddle has a stupid policy where they want to prevent usage of full HTML files. They are trying to enforce this with stupid error warnings in HTML content part. You will need to have something like firebug plugin for Firefox or Chrome to remove this stupidity. Or you can even do it with Grease Monkey plugin.
In case you want to use full HTML template like in this example: http://jsfiddle.net/Gajotres/yWTG2/ you will need to use your javascript code in onDomready state.
Some functionalities are not going to work. Like window.orientationchange event.
I have been researching all morning about integrating an android barcode scanner app into a web page, but haven't found exactly what I need to know. I want to have a web page that the user can fill in text fields by using an android barcode scanner. So the user would be on a web page and would either click inside the text field or click a button next to the text field that would start the android barcode scanner. They would then scan the barcode and the text field would be filled in.
I have found solutions on how to do this and then go to a different page, but it is important that the user stays on the same page. I have seen the zxing project and thought that might be able to be used, but I'm not sure if it allows for the page to stay the same.
I'm pretty sure this is possible and is wondering if any one could give me a high level overview on how they would do it. I was thinking it might be able to be done with an ajax request that gets submitted on a button click. The ajax request would get sent to my server, the server would send something to the android device that would start the scanner and return the data which in turn gets sent back in the ajax response. Is there any way to cut out the server though and just have the android browser starting the barcode scanner? Thank you for your time and I appreciate any discussion on it.
ZXing (zebra crossing) provides the capability to initiate the bar code scanner via a webpage through a button click event, anchor tag, or other action that could call a URL on a mobile device.
When the barcode scanner application is installed on an android device, a URL call to:
zxing://scan/?ret=http://foo.com/products/{CODE}/description&SCAN_FORMATS=UPC_A,EAN_13
Will bring up the device bar code reader, the user scans the code, and the code is returned via the callback URL parameter supplied in the zxing URL.
You can view an example (works on android) here: http://zxing.appspot.com/scan
You can try this for Android:
You can use Zxing library for barcode scan for webpages
<!DOCTYPE html>
<script type="text/javascript">
//This entire block of script should be in a separate file, and included in each doc in which you want scanner capabilities
function zxinglistener(e){
localStorage["zxingbarcode"] = "";
if(e.url.split("\#")[0] == window.location.href){
window.focus();
processBarcode(decodeURIComponent(e.newValue));
}
window.removeEventListener("storage", zxinglistener, false);
}
if(window.location.hash != ""){
localStorage["zxingbarcode"] = window.location.hash.substr(1);
self.close();
window.location.href="about:blank";//In case self.close is disabled
}else{
window.addEventListener("hashchange", function(e){
window.removeEventListener("storage", zxinglistener, false);
var hash = window.location.hash.substr(1);
if (hash != "") {
window.location.hash = "";
processBarcode(decodeURIComponent(hash));
}
}, false);
}
function getScan(){
var href = window.location.href.split("\#")[0];
window.addEventListener("storage", zxinglistener, false);
zxingWindow = window.open("zxing://scan/?ret=" + encodeURIComponent(href + "#{CODE}"),'_self');
}
</script>
<html>
<head>
<script type="text/javascript">
function processBarcode(b){
var d = document.createElement("div");
d.innerHTML = b;
document.body.appendChild(d);
}
</script>
</head>
<body>
<button onclick="getScan()">get Scan</button>
</body>
</html>
For reference: Read link
Using a javascript interface and loadurl(javascript...) you can communicate with your webpage from Android
public void loadScript(String script){
webview.loadUrl("javascript:(function() { " + script + "})()");
}
private class JavaScriptInterface {
public void startQRScan() {
...
}
}
There are plenty of examples on google.