I am trying to implement JS interface in my WebView. I created a separate class with a method which calls listener, subsequently the string caught by listener should be put in the intent (in MainActivity) and intent finishes.
MainActivity.kt:
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.webkit.JavascriptInterface
import android.webkit.WebChromeClient
import android.webkit.WebSettings
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import sbs.pros.app.databinding.ActivityMainBinding
typealias IDListener = (qr: String) -> Unit
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val answerIntent = Intent()
#SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPayBinding.inflate(layoutInflater)
val WebView = binding.webView
val webSettings: WebSettings = WebView.settings
WebView.settings.javaScriptEnabled = true
WebView.settings.javaScriptCanOpenWindowsAutomatically = true
webSettings.builtInZoomControls = false
WebView.webViewClient = WebViewClient()
WebView.webChromeClient = WebChromeClient()
WebView.addJavascriptInterface(WebAppInterface(this
) { id ->
answerIntent.putExtra("pay", id)
setResult(RESULT_OK)
finish()
}, "AndroidInterface")
WebView.setInitialScale(160)
WebView.loadUrl("https://pros.sbs/payment/create_payment.php?apicall=one_address")
setContentView(binding.root)
}
}
class WebAppInterface internal constructor(c: Context, listener: IDListener) {
var mContext: Context = c
fun WebAppInterface(context: Context) {
this.mContext = context
}
#JavascriptInterface
#SuppressWarnings("unused")
fun getID(id: String?, listener: IDListener) {
if (id != null) {
listener(id)
}
}
}
create_payment.php:
<script src="javascript.js">
function giveID(id) {
AndroidInterface.getID(id);
}
</script>
<?php
if(null !==filter_input(INPUT_GET, 'apicall')){
switch(filter_input(INPUT_GET, 'apicall')){
case 'one_address':
?>
<script src="javascript.js">
giveID('some_id');
</script>
<?php
break;
}
}
The intent then should finish, showing a result (String) in a separate TextView. Unfortunately, that does not happen and the result returned is null. Please help me to find the problem with the interface.
I'd like to import a module written natively (java, Android) into my React Native sources, in JS.
To access your functionality implemented in java you have to create a bridge. You can see the most recent instructions in the RN documentation site*.
The steps, assuming React Native 0.61, for a hello world, to be implemented in the android project inside the react native app directory (android directory):
1) First you create a simple POJO class to be returned to the react native context:
class MyData{
private int timeSpentSleeping;
public int getTimeSpentSleeping() {
return timeSpentSleeping;
}
public void setTimeSpentSleeping(int timeSpentSleeping) {
this.timeSpentSleeping = timeSpentSleeping;
}
#NonNull
#Override
public String toString() {
Gson gson = new Gson();
String json = gson.toJson(this);
return json;
}
static MyData build(final int timeSpentSleeping){
MyData newInstance = new MyData();
newInstance.timeSpentSleeping = timeSpentSleeping;
return newInstance;
}
}
And the react native module that do something and return objects of this class as javascript Promises:
public class HelloPromiseModule extends ReactContextBaseJavaModule {
public HelloPromiseModule(#NonNull ReactApplicationContext reactContext) {
super(reactContext);
}
#NonNull
#Override
public String getName() {
return "HelloPromise";
}
#ReactMethod
public void foobar(Promise promise){
Random r = new Random();
final int timeToSleep = r.nextInt(1000);
runThreadAndCallPromiseToJavascript(timeToSleep, promise);
}
//Cria um thread pra executar algo em paralelo
private void runThreadAndCallPromiseToJavascript(final int timeToSleep,final Promise promise){
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(timeToSleep);
MyData result = MyData.build(timeToSleep);
promise.resolve(result.toString());
} catch (InterruptedException e) {
e.printStackTrace();
promise.reject(e);
}
}
});
t.run();
}
}
Now, we create the React Native Package (that is different from java packages):
public class HelloWorldPackage implements ReactPackage{
#NonNull
#Override
public List<NativeModule> createNativeModules(#NonNull ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(
new HelloPromiseModule(reactContext));
}
#NonNull
#Override
public List<ViewManager> createViewManagers(#NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
The last step in the android version of your react native app is to register your HelloWorldPackage:
In the MainApplication.java inside your android project, inside the getPackages(), in the list of packages (new PackageList(this)...):
packages.add(new HelloWorldPackage());
Something like that:
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new HelloWorldPackage());
return packages;
}
Now, to get your native class in the javascript world:
import {
NativeModules,
} from 'react-native';
...
const {HelloPromise} = NativeModules;
Your native class is accessible from the variable HelloPromise.
You can get the result of HelloPromise.foobar() with something like this, in the react native side of your code:
async function handleHelloPromisesPress() {
let result = await HelloPromise.foobar();
console.log(result);
}
You may notice that 'result' is a json whose structure is equal to the POJO class we created in the beginning.
When I click the ListView, I'd like to start a new Activity
Here is my MainActivity.java
package com.theheran.listviewicon;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity {
//Declarasi Array Menu dan gambar
ListView list;
String[] menu = {
"#The_Heran",
"www.theheran.com",
"Add",
"Delete",
"Next",
"Back",
"Find",
"Warning"
} ;
Integer[] imageId = {
R.drawable.ic_launcher,
R.drawable.signal,
R.drawable.add,
R.drawable.trash,
R.drawable.next,
R.drawable.back,
R.drawable.find,
R.drawable.warning
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomListView adapter = new
CustomListView(MainActivity.this, menu, imageId);
list=(ListView)findViewById(R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
Toast.makeText(MainActivity.this, "You Clicked at " +menu[+ position], Toast.LENGTH_SHORT).show();
// HERE THE PROBLEM (Intent)
Intent intent = new CustomListView(MainActivity.this,);
startActivity(intent);
}
});
}
}
My CustomListView
package com.theheran.listviewicon;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class CustomListView extends ArrayAdapter<String> {
//Declarasi
private final Activity context;
private final String[] web;
private final Integer[] imageId;
public CustomListView(Activity context,String[] web, Integer[] imageId) {
super(context, R.layout.list_single_data, web);
this.context = context;
this.web = web;
this.imageId = imageId;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
//Load Custom Layout untuk list
View rowView= inflater.inflate(R.layout.list_single_data, null, true);
//Declarasi komponen
TextView txtTitle = (TextView) rowView.findViewById(R.id.txtList);
ImageView imageView = (ImageView) rowView.findViewById(R.id.imgIcon);
//Set Parameter Value
txtTitle.setText(web[position]);
imageView.setImageResource(imageId[position]);
return rowView;
}
}
// HERE THE PROBLEM (Intent)
Intent intent = new CustomListView(MainActivity.this,);
startActivity(intent);
Here you are trying to use a wrong structure.
Use this:
Intent intent = new Intent(MainActivity.this, NextActivity.class);
MainActivity.this.startActivity(intent );
Try this way ,
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Toast.makeText(MainActivity.this, "You Clicked at " +position , Toast.LENGTH_SHORT).show();
Intent MoveToNext = new Intent(getApplicationContext(), Your_Next_Activity.class);
startActivity(MoveToNext);
}
});
This is how I have done it. You start a new activity using the startActivityForResult(intent, 2); Where you throw a intent and a number (number that you check for when you go back to the starting page).
private void registerButtonClickList() {
ListView list = (ListView) findViewById(R.id.listView);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(InThisClass.this, GoingToThisClass.class);
intent.putExtra("Position", position);
startActivityForResult(intent, 0);
}
});
}
Use this where in the same class as you started the other one form the list. This is needed since you are expecting a return when you start with startActivityForResult()
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0) {
if (resultCode == Activity.RESULT_OK) {
//See what u should do using the requestCode
//and check if it ended OK
}
if (resultCode == Activity.RESULT_CANCELED) {
//what you do when canceled
}
}
}
And in the activity that you started you need to end with this because you are expected to return something. This you do by using setResult().
Button btn = (Button) findViewById(R.id.btn);
btnCANCEL.setOnClickListener(new View.OnClickListener() {
#TargetApi(Build.VERSION_CODES.CUPCAKE)
#Override
public void onClick(View v) {
Intent intent = new Intent();
setResult(Activity.RESULT_OK, intent);
//intent.putExtra("something", something); if you need to send something back
finish();
}
});
Hope this helps!
Im trying to send notifications to a Titanium App from AeroGear. After getting the token, how can subscribe to the channel?
Obteining the token:
var CloudPush = require('ti.cloudpush');
var deviceToken = null;
CloudPush.retrieveDeviceToken({
success: deviceTokenSuccess,
error: deviceTokenError
});
function deviceTokenSuccess(e) {
deviceToken = e.deviceToken;
}
function deviceTokenError(e) {
alert('Failed to register for push notifications! ' + e.error);
}
CloudPush.addEventListener('callback', function (evt) {
alert("Notification received: " + evt.payload);
});
This is the example code for native Androiod:
package com.push.pushapplication;
import java.net.URI;
import java.net.URISyntaxException;
import org.jboss.aerogear.android.unifiedpush.PushConfig;
import org.jboss.aerogear.android.unifiedpush.PushRegistrar;
import org.jboss.aerogear.android.unifiedpush.Registrations;
import android.app.Application;
public class PushApplication extends Application {
private final String VARIANT_ID = "variant_id";
private final String SECRET = "secret";
private final String GCM_SENDER_ID = "1";
private final String UNIFIED_PUSH_URL = "URL";
private PushRegistrar registration;
#Override
public void onCreate() {
super.onCreate();
Registrations registrations = new Registrations();
try {
PushConfig config = new PushConfig(new URI(UNIFIED_PUSH_URL), GCM_SENDER_ID);
config.setVariantID(VARIANT_ID);
config.setSecret(SECRET);
config.setAlias(MY_ALIAS);
registration = registrations.push("unifiedpush", config);
registration.register(getApplicationContext(), new Callback() {
private static final long serialVersionUID = 1L;
#Override
public void onSuccess(Void ignore) {
Toast.makeText(MainActivity.this, "Registration Succeeded!",
Toast.LENGTH_LONG).show();
}
#Override
public void onFailure(Exception exception) {
Log.e("MainActivity", exception.getMessage(), exception);
}
});
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
Really lost here, any help would be appreciated!
You need to make wrapper around AeroGear native library as titanium module. However, it may be difficult if you didn't it before.
The titanium module that you need to get this working has been made by "Mads" and you can find it here: https://github.com/Napp/AeroGear-Push-Titanium
Am working on app which i recently implemented a background service with help from the following: https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/
Everything works fine and the service runs in the background when the phone is restarted.
But in the background service which executes a Java method Every 5mins 'DoWork' Line 20 https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/blob/master/2.2.0/MyService.java
package com.yournamespace.yourappname;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import com.red_folder.phonegap.plugin.backgroundservice.BackgroundService;
public class MyService extends BackgroundService {
private final static String TAG = MyService.class.getSimpleName();
private String mHelloTo = "World";
#Override
protected JSONObject doWork() {
JSONObject result = new JSONObject();
try {
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
String now = df.format(new Date(System.currentTimeMillis()));
String msg = "Hello " + this.mHelloTo + " - its currently " + now;
result.put("Message", msg);
Log.d(TAG, msg);
} catch (JSONException e) {
}
return result;
}
#Override
protected JSONObject getConfig() {
JSONObject result = new JSONObject();
try {
result.put("HelloTo", this.mHelloTo);
} catch (JSONException e) {
}
return result;
}
#Override
protected void setConfig(JSONObject config) {
try {
if (config.has("HelloTo"))
this.mHelloTo = config.getString("HelloTo");
} catch (JSONException e) {
}
}
#Override
protected JSONObject initialiseLatestResult() {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onTimerEnabled() {
// TODO Auto-generated method stub
}
#Override
protected void onTimerDisabled() {
// TODO Auto-generated method stub
}
}
I would like to call a JavaScript function also from that method.
The Javascript Function does the following:
- Gets all the device contacts
- Get the device GeoLocation
- Get the device IMEI and phonenumber
and post to an external server.
I would like to know if that is possible i.e calling the javascript function from Java.
Note: I do not know much about Java so detailed explanation will be appreciated.
Thanks in advance !