Cordova plugin, using javascript to start an android service - javascript

I have some issues developing my own plugin. I want my plugin to run as a background process on an android device. Searching the internet, I found using the Service superclass (or a sub-class) being most relevant. Below is some sample code, the execute method in Hello.java is successfully called - the app crashes when I try to start the service (the constructor is successfully instantiated though). Any hints?
//Myservice.java
public class MyService extends IntentService {
public MyService(String name) {
super(name);
Log.d("asd", "constructor");
}
#Override
public void onHandleIntent(Intent intent) {
Log.d("asd", "something");
}
}
//Hello.java
public class Hello extends CordovaPlugin {
#Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
Log.d("asd", "we are in execute, hurray!");
Context context = cordova.getActivity().getApplicationContext();
Intent intent = new Intent(context, MyService.class);
MyService service = new MyService("WifiP2pService");
//either this
service.startService(intent);
//or this, tried both
//context.startService(intent);
return true;
}
}
// /plugins/the.package/www/hello.js
module.exports = {
greet: function (name, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "Hello", "greet", [name]);
}
};
// /www/index.js - in onDeviceReady function
var success = function(message) {
alert(message);
}
var failure = function() {
alert("Error calling the plugin");
}
hello.greet("Superdids", success, failure);
I am fairly new to android programming, so any hints would be muchly appreciated!

Related

Error on cordova plugin: callback returning error

On my www/RuptionARPlugin.js file I have the followig code:
RuptionARPlugin.prototype.loadWorld = function(successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "RuptionARPlugin", "open", []);
// We add an event listener on the resume and pause event of the application life-cycle
document.addEventListener("resume", this.onResume, false);
document.addEventListener("pause", this.onPause, false);
document.addEventListener("backbutton", this.onBackButton, false);
};
On my RuptionARPlugin.java I have the following
(...)
public class RuptionARPlugin extends CordovaPlugin {
(...)
private static final String ACTION_OPEN = "open";
(...)
private HelloARRuption helloARRuption
(...)
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
(...)
if (RuptionARPlugin.ACTION_OPEN.equals(action)) {
this.openCallback = callbackContext;
boolean cameraPermissionRequesrRequired = !cordova.hasPermission(Manifest.permission.CAMERA);
_locationPermissionRequestRequired = !cordova.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION) && !cordova.hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION);
if(cameraPermissionRequesrRequired && _locationPermissionRequestRequired) {
_cameraPermissionGranted = false;
this.cordova.requestPermissions(this, CAMERA_PERMISSION_REQUEST_CODE, new String[] {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION} );
} else if (cameraPermissionRequesrRequired) {
this.cordova.requestPermissions(this, CAMERA_PERMISSION_REQUEST_CODE, new String[] {Manifest.permission.CAMERA});
} else if (_locationPermissionRequestRequired) {
_cameraPermissionGranted = true;
this.cordova.requestPermissions(this, CAMERA_PERMISSION_REQUEST_CODE, new String[] {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION});
} else {
helloARRuption.onSurfaceCreated(render);
helloARRuption.onSurfaceChanged(render, width, height);
helloARRuption.onDrawFrame(render);
}
return true;
}
(...)
}
(...)
protected static class HelloARRuption extends HelloArActivity {
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!hasFocus) {
this.getCurrentFocus();
}
}
#Override
protected void onResume() {
super.onResume();
}
}
(...)
}
On my library file, I have the definition of HelloARActivity classes.
When I generate the plugin and add it to a project, the callback I receive is the error one. I don't know what happens inside the open function.
My Cordova plugin is on https://github.com/ruption-lda/ruption-ar-cordova-plugin
Can someone please help?

Check valid SignalR connection using IHubContext from a Hosted Service

I have a hosted service sending messages to the client via SignalR and the client is picking them up and displaying on a razor page. Here is the stripped down version.
This works well except that the .js file is called AFTER the hosted service is instantiated which means the connection is not established in time for the first messages so these are lost.
Is there a way to check the connection using IHubContext before I send anything? Or do I need a more fundamental change to the whole approach?
Javascript (linked to the Index page)
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/logHub").build();
connection.start()
connection.on("ReceiveLogNotification", function (msg) {
console.log("JS: " + msg);
});
Hub class
public class LogHub : Hub
{
}
Hosted Service
public class MsgGenerator : IHostedService
{
private Random _random;
private Microsoft.Extensions.Logging.ILogger _logger;
private Timer? _timer;
private readonly IHubContext<LogHub> _hubContext;
public LogGenerator(ILogger<LogGenerator> logger,
IHubContext<LogHub> hubContext)
{
_logger = logger;
_random = new Random();
_timer = null;
_hubContext = hubContext;
}
public Task StartAsync(CancellationToken cancellationToken)
{
ScheduleNextMessage();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
private void ScheduleNextMessage()
{
var nextTime = TimeSpan.FromMilliseconds(_random.Next(1000));
_timer = new Timer((state) => { GenerateMessage(); }, null, nextTime, TimeSpan.Zero);
}
private async void GenerateMessage()
{
await _hubContext.Clients.All.SendAsync("ReceiveLogNotification", "test message");
ScheduleNextMessage();
}

Android music streamer

Hi I'm building a react native android module for music streaming. When I try to stream music, it works with the first URL that I load but when I try to load another URL, the app crashes.
Here's the code for the module.
package com.mediaplayer;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.io.IOException;
public class MediaPlayerModule extends ReactContextBaseJavaModule {
String stream = "http://stream.radioreklama.bg:80/radio1rock128";
boolean prepared = false;
boolean started = false;
MediaPlayer mediaPlayer;
PlayerTask playerTask;
public MediaPlayerModule(ReactApplicationContext reactContext) {
super(reactContext);
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
#Override
public String getName() {
return "MediaPlayerModule";
}
#ReactMethod
public void play(String url) {
if(prepared){
mediaPlayer.reset();
mediaPlayer.release();
}
playerTask = new PlayerTask();
playerTask.execute(url);
}
#ReactMethod
public void pause() {
if(mediaPlayer != null){
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
#ReactMethod
public void resume() {
if (started) {
mediaPlayer.start();
}
}
#ReactMethod
public void destroy() {
if (prepared) {
mediaPlayer.release();
started = false;
}
}
class PlayerTask extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... strings) {
Boolean prepared = false;
try {
mediaPlayer.setDataSource(strings[0]);
mediaPlayer.prepare();
prepared = true;
} catch (IOException e) {
e.printStackTrace();
prepared = false;
}
return prepared;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
mediaPlayer.start();
started = true;
}
}
}
There's a page that has the songs and their URLs. When I select a song on the first page, it navigates to the second page with the URL of the song. Here's the js code for the second page(the page that plays the songs):
var mp = require('react-native').NativeModules.MediaPlayerModule;
export default class Player extends Component {
constructor(props) {
super(props);
this.state = {
image: this.props.navigation.state.params.image,
title: this.props.navigation.state.params.title,
artistes: this.props.navigation.state.params.artistes,
mp3Url:this.props.navigation.state.params.mp3Url
}
}
componentDidMount(){
mp.play(this.state.mp3Url);
}
}
EDIT: Here's the logcat:
--------- beginning of crash
06-17 07:21:28.544 2406-2432/com.downstream E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
Process: com.downstream, PID: 2406
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalStateException
at android.media.MediaPlayer.nativeSetDataSource(Native Method)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1085)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1046)
at com.mediaplayer.MediaPlayerModule$PlayerTask.doInBackground(MediaPlayerModule.java:118)
at com.mediaplayer.MediaPlayerModule$PlayerTask.doInBackground(MediaPlayerModule.java:112)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
at java.lang.Thread.run(Thread.java:818) 
06-17 07:21:28.914 2406-2428/com.downstream E/Surface: getSlotFromBufferLocked: unknown buffer: 0xae6b5f10
It might be crashing because next time when you play Second song, it might be getting "NULL" object of Mediaplayer. Please post Your logcat with crashes so that i can be more sure on my answer.
#Rahul Gupta's comments led me to thinking about the problem in the right way. So the problem was I was doing the check for prepared in the wrong place. All I needed to do was to move the if(prepared) else block into my async task and it solved the problem. Here's the code:
This is what the play method looks like now:
#ReactMethod
public void play(String url) {
playerTask = new PlayerTask();
playerTask.execute(url);
}
and here's the ASYNC task:
class PlayerTask extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... strings) {
if(prepared){
mediaPlayer.reset();
}
try {
mediaPlayer.setDataSource(strings[0]);
mediaPlayer.prepare();
mediaPlayer.start();
prepared = true;
} catch (IOException e) {
e.printStackTrace();
prepared = false;
}
return prepared;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
}
}

displaying data from restful service in react UI through nodejs

I've developed a restful webservice which displays a simple data using below code.
package com.mike;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MessageController {
#RequestMapping(value="/message",method=RequestMethod.GET)
public Message print(){
return new Message(1,"Hello Mike!!");
}
}
and the bean is as follows....
package com.mike;
public class Message {
private int id;
private String message;
public Message(int id, String message){
this.id=id;
this.message=message;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMesssage(String message) {
this.message = message;
}
}
now I want to display this data in an Nodejs application, so I wrote a file named app.js and wrote the following code to display data in the console.and it worked fine. but i don't know how to integrate this nodejs application with reactjs UI so that i can display in on a web page. so please kindly help me, I am new to both node and react.the code for app.js is below...
var http=require('http');
var extServerOptions={
host:'localhost',
port:'8080',
path:'/message',
method:'GET'
};
var mes=[];
var x;
var text="";
function get(){
http.request(extServerOptions,function (res){
res.setEncoding('utf8');
res.on('data',function(data){
mes=JSON.parse(data);
console.log(mes);
for(x in mes){
text+=mes[x]+" ";
};
console.log(text);
});
}).end();
};
get();
please kindly say me the stepps i need to do in order to display data in a react page.

How to set up retrofit for my application?

I am just learning about Retrofit and Android development. What I would like to do is send a fairly complex JSON object to a server from a website and be able to retrieve it using Retrofit as a Java Object for my Android Application.
So basically something like this,
Website JSON --Ajax Call--> Server --Retrofit--> Android Application (Java Object / Collection)
Which server would be the best to set this up? Also are there any good references on how to accomplish this?
Thank you
With retrofit and android, you only need a couple of things
A java model
public class User {
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
//Getters and setters
//...
}
A retrofit interface
public interface APIService {
#FormUrlEncoded
#Headers("Accept: application/json")
#POST("register")
Call<AuthRegister> createUser(
#Field("name") String name,
#Field("password") String password
);
}
A callback for retrofit
public class AuthRegister {
#SerializedName("message")
#Expose
private String message;
#SerializedName("errors")
#Expose
private Errors errors;
public String getMessage() {
return message;
}
public Errors getErrors() {
return errors;
}
}
A network client
public class NetworkClient {
public static Retrofit retrofit;
/*
This public static method will return Retrofit client
anywhere in the appplication
*/
public static Retrofit getRetrofitClient() {
//If condition to ensure we don't create multiple retrofit instances in a single application
if (retrofit == null) {
//Defining the Retrofit using Builder
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.level(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
// .addInterceptor(interceptor)
.connectTimeout(30, TimeUnit.MINUTES)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(Config.BASE_URL) //This is the only mandatory call on Builder object.
.client(client)
.addConverterFactory(GsonConverterFactory.create()) // Convertor library used to convert response into POJO
.build();
}
return retrofit;
}
}
The call inside the activity you are to display the response or save the data
private void saveUser(String name, String password){
Retrofit retrofit = NetworkClient.getRetrofitClient();
APIService service = retrofit.create(APIService.class);
Call<AuthRegister> call = service.createUser(name, password);
call.enqueue(new Callback<AuthRegister>() {
#Override
public void onResponse(Call<AuthRegister> call, Response<AuthLogin> response) {
if (response.code() == 200) {
if (response.body().getMessage() != null) {
Toast.makeText(mContext, "Success", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "Could not save user", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(mContext, "Could not save user", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<AuthRegister> call, Throwable t) {
new PrefManager(mContext).clearUser();
Log.e(TAG, t.toString());
Toast.makeText(mContext, "Could not save user", Toast.LENGTH_SHORT).show();
}
});
}
You can use any server as you need. Any complex JSON can be handled by retrofit library. Check the Following link Retrofit android example web services

Categories