Looking at my debug message in Terminal using $ adb logcat -s "app" and $ adb logcat -s Unity, I have noticed that my JAR file is only consulted once when I first build my app to Android (.APK) but every time afterward that I just run my app, the plug-in JAR file is not consulted. Why is that?
public class MyClass
{
public static void MyMethod()
{
Log.i("app", "MyMethod entered");
if (blah)
{
Log.d("app", "If entered");
}
else
{
Log.e("app", "Else entered");
}
blah
}
}
Using $ adb logcat -s "app" I see Log.i and Log.d messages, and below in my Unity3D code, I see the Debug.Log message using $ adb logcat -s Unity
public class MyUnityClass : MonoBehaviour
{
public static void MyUnityMethod()
{
#if UNITY_ANDROID
try
{
using ( AndroidJavaObject androidJavaObject = new AndroidJavaObject("com.example.unityplugin.MyClass") )
{
if (androidJavaObject != null)
{
androidJavaObject.CallStatic("MyMethod");
Debug.Log("androidJavaObject != null SUCCESS!");
}
}
}
catch (Exception e)
{
Debug.LogException(e);
}
#endif
}
}
Every time I run my app on the tablet, a script calls MyUnityMethod() which in turn calls MyMethod() of my JAR, but after the first build, I never see those debug messages again...
You have to use AndroidJavaClass instead of AndroidJavaObject. Also, don't create and destroy the Object each time. Don't enclose the code with the using statement. Just declare the variable as a global variable then re-use it.
Java:
public class MyClass
{
public static void MyMethod()
{
Log.i("app", "MyMethod entered");
}
}
C#:
AndroidJavaClass customClass;
void Start()
{
//Replace with your full package name
customClass = new AndroidJavaClass("com.example.unityplugin.MyClass");
//Call function
MyMethod();
}
public void MyMethod()
{
customClass.CallStatic("MyMethod");
}
If you need the MyMethod function to be static then make the customClass variable static too:
C#:
static AndroidJavaClass customClass;
void Start()
{
//Replace with your full package name
customClass = new AndroidJavaClass("com.example.unityplugin.MyClass");
//Call function
MyMethod();
}
public static void MyMethod()
{
customClass.CallStatic("MyMethod");
}
Related
I am using Wootrick SDK for create a bridge to react native. When I'm calling a specific function I'm getting following log and Wootric Survey doesn't show.
java.lang.IllegalStateException: Method addObserver must be called on the main thread
My code as follows,
#ReactMethod
public void configureWithClientID(String clientId, String accountToken) {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
Log.e("WOOTRIC", "Current activity is null");
return;
}
try {
wootric = Wootric.init(currentActivity, clientId, accountToken);
} catch (Exception e) {
Log.e("WOOTRIC", e.toString());
}
}
Can someone help me to solve the above issue.
You can execute the Wootric initialization code on the main thread with something like this:
currentActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
// initialize Wootric here
}
});
I have a problem when i try to go back from a cordova plugin integrated on cordova. When i try to do it, the app crashes, I debugged first the javascript and then the native code that javascript call and this is the instruction that make app crash.
cordova.getActivity().finish();
This is in TestPlugin.java file in this most global context:
if (action.equals("open")) {
try {
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(cordova.getActivity(),
PhemiumEnduserActivity.class);
cordova.getActivity().startActivity(intent);
cordova.getActivity().overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
});
callback.success("");
} catch (final Exception e) {
callback.error(e.getMessage());
}
}
else if( action.equals("exit_app") ) {
try {
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
cordova.getActivity().finish();
}
});
callback.success("");
} catch (final Exception e) {
callback.error(e.getMessage());
}
}
When the app calls the plugin executes the "open" part and when i click the back button makes the "exit_app" part and then on cordova.getActivity().finish(); app crashes with no error on the android studio console. There is no signal of webview close. What i'm doing wrong? Why it crashes?
Please post full plugin code or repository, but i think is because you try to finish activity in another thread, or activity no more exist (getActivity return null).
You need to try with somewhat like this:
protected Activity mActivity;
....
else if( action.equals("exit_app") ) {
mActivity = cordova.getActivity();
try {
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
if(mActivity!=null)
mActivity.finish();
}
});
callback.success("");
} catch (final Exception e) {
callback.error(e.getMessage());
}
}
For more trace info try to open android project in Android studio and debug it.
I want to know, does any way exist to communicate with system during instrumentation test execution.
For example:
I have a phone with IR port on onboard & I can work with it through private SDK, also I can tune it with my application. In my Instrumentation test cases I want test app behavior based on external events which I want to configure before test separate test execution.
It's looks like
#Test
public void test() throws Exception {
setupExternalCondition(condition1_ON); // setup external transiver
assertNotNull(IR.read());
assertTrue(assertIR.write());
setupExternalCondition(condition1_OFF);
assertNotNull(IR.read());
assertFalse(IR.write());
}
It's very simple example but there is a lot of "conditions", and sdk updating frequencies to high. I can't do all of this verification manually, and can't ask "transiver&SDK team" make a mock states list for writing just a unit test for coverage. So I want somehow inject external component execution to TestRuner for receiving events(or testName before test case execution) on local machine(or CI machine) to setup external condition.
Simple solution(I think) to run a tcp server on appUnderTest and request external condition change - I am not sure does it possible, and not sure about stable connection(wifi), so may be it's possible to do over adb.
Any suggestions?
P.S: test device has root permissions.
So, find not bad but not ideal solution.
Still wait for better proposition, if not may be this answer will be helpful for someone;
For "building the bridge" between local machine and AndroidJUnitTest I add next class to tests:
class IPCServiceBridge extends BroadcastReceiver {
private static final String FILTER_ID = "IPC_SERVICE";
private static IPCServiceBridge sInstance;
private boolean mIsPermitted;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("ipc.service.action")) {
mIsPermitted = true;
}
}
public static IPCServiceBridge getInstance() {
if (sInstance == null) {
sInstance = new IPCServiceBridge();
IntentFilter filter = new IntentFilter();
filter.addAction("ipc.service.action");
Context context = InstrumentationRegistry.getContext();
context.registerReceiver(sInstance, filter);
}
return sInstance;
}
public void sendIpcCommand(String commandName) {
try {
int i = 30;
mIsPermitted = false;
while (i > 0) {
pub("request:" + commandName);
Thread.sleep(1000);
if (mIsPermitted) {
break;
}
i--;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!mIsPermitted) {
throw new RuntimeException("IPC service does not respond");
}
}
private static void pub(String msg) {
Log.e(FILTER_ID, msg);
}
}
Than I start adb logcat -s "filter_name", parse and check which condition should be applied for InsttUnit test. When conditions is ready i send back broadcast receiver with required action.
#Test
public void test2() throws Exception {
IPCServiceBridge.getInstance().sendIpcCommand("CONDITION#123");
}
Work good, but I'm not sure that it will be super stable.
FATAL EXCEPTION: Thread-5195
java.lang.NullPointerException: src == null
at java.lang.System.arraycopy(Native Method)
at com.paypal.android.a.g.a(Unknown Source)
at com.paypal.android.a.h.c(Unknown Source)
at com.paypal.android.MEP.PayPal.setLanguage(Unknown Source)
at com.paypal.android.MEP.PayPal.initWithAppID(Unknown Source)
at com.lonfun.pets.UnityPayMenuActivity.initLibrary(UnityPayMenuActivity.java:256)
at com.lonfun.pets.UnityPayMenuActivity.access$2(UnityPayMenuActivity.java:249)
at com.lonfun.pets.UnityPayMenuActivity$2$1.run(UnityPayMenuActivity.java:175)
I just use android to open paypal, everything is ok, but if I call from unity, this is happened!
this is my java code:
package com.paypal.androidpets;
import android.content.Context;
import android.os.Handler;
import com.lonfun.pets.UnityPayMenuActivity;
import com.paypal.android.MEP.PayPal;
import com.paypal.android.MEP.PayPalActivity;
public class PaypalTool {
Context context;
PayPal pp;
private static final int server = PayPal.ENV_SANDBOX;
// The ID of your application that you received from PayPal
private static final String appID = "APP-80W284485P519543T";
public PaypalTool(Context context) {
this.context=context;
}
public void initLibrary(final Handler handler)
{
new Thread() {
public void run() {
PayPalActivity._paypal = null;
pp = PayPal.getInstance();
// If the library is already initialized, then we don't need to initialize it again.
if(pp == null) {
// pp = PayPal.initWithAppID(context, "", PayPal.ENV_NONE);
pp = PayPal.initWithAppID(context, appID, server);
pp.setShippingEnabled(false);
}
if (PayPal.getInstance().isLibraryInitialized()) {
handler.sendEmptyMessage(0);
}
else {
handler.sendEmptyMessage(1);
}
}
}.start();
}
}
has anybody solve this problem,,please help me, thank you!
using UnityEngine;
using System.Collections;
public class PayMoneyHandler : MonoBehaviour
{
#if UNITY_ANDROID
static AndroidJavaClass payPluginClass;
static AndroidJavaClass unityPlayer;
static AndroidJavaObject currActivity;
#endif
public static void Pay(string productID)
{
#if UNITY_ANDROID
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
jo.Call("StartActivity0",
"com.peten.tier2",
"EGAHCNJDEJBWBIBWEXIKDEGLJECOAD.Mac",
"Dog",
"AndDogCn",
"http://42.121.94.123/TradeWeb/AlipayTrade.aspx",
"http://58.246.188.238/TradeWeb/PaypalTrade.aspx"
);
#endif
}
}
using UnityEngine;
using System.Collections;
public class TestForPaypal : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void OnClick(){
Debug.Log("Test For Paypal!");
PayMoneyHandler.Pay("test1");
}
}
public void StartActivity0(final String name,final String PlayerName,final String GameID,final String ZoneID,final String payUrl,final String paypalUrl)
{
this.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i("Order", "name:"+name+"PlayerName:"+PlayerName+"GameID:"+GameID+"ZoneID:"+ZoneID+"payUrl:"+payUrl+"paypalUrl:"+paypalUrl);
Intent payintent=new Intent(mContext,UnityPayMenuActivity.class);
payintent.putExtra("name",name);
payintent.putExtra("PlayerName",PlayerName);
payintent.putExtra("GameID",GameID);
payintent.putExtra("ZoneID",ZoneID);
payintent.putExtra("payUrl",payUrl);
payintent.putExtra("paypalUrl",paypalUrl);
Unity3DMainActiviy.this.startActivity(payintent);
}
});
}
I think you didnot enter the appID and the server detail.
Below is the working code which i have implement and It works fine for me.
I have implement Pay on button click which extends the runnable
Check_out.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (_paypalLibraryInit) {
showPayPalButton();
//Toast.makeText(Android_PP_Test1Activity.this, captions[position], Toast.LENGTH_SHORT).show();
}
else {
// Display a progress dialog to the user and start checking for when
// the initialization is completed
Thread initThread = new Thread(initLibraryRunnable);
initThread.start();
_progressDialog = new ProgressDialog(Recharge.this);
_progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
_progressDialog.setMessage("Loading PayPal Payment Library");
_progressDialog.setCancelable(false);
_progressDialog.show();
_progressDialogRunning = true;
Thread newThread = new Thread(checkforPayPalInitRunnable);
newThread.start();
//Toast.makeText(Android_PP_Test1Activity.this, "Picasso Paintings", Toast.LENGTH_SHORT).show();
}
}
});
This button call this runnable method
//This lets us run the initLibrary function
final Runnable initLibraryRunnable = new Runnable() {
public void run() {
initLibrary();
}
};
and this method is responsible to initiate the initLibrary.
/** init method **/
public void initLibrary() {
PayPal pp = PayPal.getInstance();
if (pp == null) {
// This is the main initialization call that takes in your Context,
// the Application ID, and the server you would like to connect to.
pp=PayPal.initWithAppID(this,"APP80W284485P519543T",PayPal.ENV_SANDBOX);
// -- These are required settings.
pp.setLanguage("en_US"); // Sets the language for the library.
// --
// -- These are a few of the optional settings.
// Sets the fees payer. If there are fees for the transaction, this
// person will pay for them. Possible values are FEEPAYER_SENDER,
// FEEPAYER_PRIMARYRECEIVER, FEEPAYER_EACHRECEIVER, and
// FEEPAYER_SECONDARYONLY.
pp.setFeesPayer(PayPal.FEEPAYER_EACHRECEIVER);
// Set to true if the transaction will require shipping.
pp.setShippingEnabled(true);
// Dynamic Amount Calculation allows you to set tax and shipping
// amounts based on the user's shipping address. Shipping must be
// enabled for Dynamic Amount Calculation. This also requires you to
// create a class that implements PaymentAdjuster and Serializable.
pp.setDynamicAmountCalculationEnabled(false);
// --
}
}
Hope It helps...
The problem is when unity generates the apk file. I have compared one apk i made miself with PayPal integration only compiling with eclipse and other compiling with Unity.
Lets say the apk i made only with eclipse is called "PayPalOnlyEclipse.apk" and the one made with unity "PayPalWithUnity.apk"; y renamed them to "PayPalOnlyEclipse.zip" and "PayPalWithUnity.zip", then open both with WinRar to compare them.
I found that PayPalOnlyEclipse had one folder that PayPalWithUnity didn't, the folder is "com\paypal\android\utils\data". So I decompressed that folder and then added it to PayPalWithUnity. Then erase the META-INF folder (the signing), then close the "PayPalWithUnity.zip" and rename it like it was before ("PayPalWithUnity.apk").
Then I used the command for signing the apk file:
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my.keystore PayPalWithUnity.apk user
Finally I used the command for zipalign:
zipalign -v 4 PayPalWithUnity.apk PayPalWithUnity2.apk
that command generates PayPalWithUnity2.apk and that is the apk file you have to install in your phone.
Hope it helps, and sorry for my english.
Check if you have included the PaypalActivity on manifest file. Like this:
<activity android:name="com.paypal.android.MEP.PayPalActivity"
android:configChanges="keyboardHidden|orientation" />
If you have it and it doesnt work yet, include the library on the build path (Properties>>Java Buid Path>>Libraries>>Add JARs) and add it on the "order and export" tab (Properties>>Java Buid Path>>Order and Export).
I need to get access to com.android.internal.telephony.Call.
doing so:
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones (this);
// Get the default phone
Phone phone = PhoneFactory.getDefaultPhone ();
CallManager mCM = CallManager.getInstance ();
mCM.registerPhone (phone);
Call call = mCM.getFirstActiveBgCall();
but does not extend to initialize the framework.
Help me to initialize Call.
I need to read the state of the call like:
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING.
You need to make use of PhoneStateListener
It will provide you the facility to have your application listen for different state of a phone call. You will need to put <uses-permission android:name="android.permission.READ_PHONE_STATE"/> in your manifest file
You can but there is a critical requirement: the application must be signed at system level, meaning you are the manufacturer.
Here is how you write a Service that will broadcast an intent for every change in the foreground call state.
/*
* This implementation uses the com.android.internal.telephony package: you have
* to extract the framework classes .jar file from the platform (or the
* emulator) to compile this code. Also, add the jar file to the external
* libraries in the Java Build Path/libraries of the android project. </p>
*
* The jar file must match the android version you are building the application
* for. Because this implementation is using the internal packages it cannot be
* guaranteed to operate on later versions of android.
*/
public class CallStateNotificationService extends Service {
private static final String LOG_TAG = CallStateNotificationService.class.getSimpleName();
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if (msg.what == 101) {
CallManager callManager = CallManager.getInstance();
Call.State state = callManager.getActiveFgCallState();
Intent intent = new Intent(PhoneIntents.ACTION_PRECISE_CALL_STATE);
intent.putExtra(PhoneIntents.PRECISE_CALL_STATE, state.name());
Context context = getApplicationContext();
context.sendBroadcast(intent);
}
}
};
#Override
public void onCreate() {
super.onCreate();
try {
CallManager callManager = CallManager.getInstance();
if (callManager != null) {
callManager.registerForPreciseCallStateChanged(mHandler, 101, null);
} else {
Log.w(LOG_TAG, "Can't resolve CallManager reference"); //$NON-NLS-1$
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onDestroy() {
super.onDestroy();
CallManager callManager = CallManager.getInstance();
if (callManager != null) {
callManager.unregisterForPreciseCallStateChanged(mHandler);
} else {
Log.w(LOG_TAG, "Can't resolve CallManager reference"); //$NON-NLS-1$
}
}
And here is the definition of the custom broadcasted intents.
/** Intent action and extra argument names for CallStateNotificationService */
public final class PhoneIntents {
public static final String ACTION_PRECISE_CALL_STATE = "com.myorg.myapp.CALL_STATE";
public static final String PRECISE_CALL_STATE = "precise_call_state";
}
To have this code compile and link, you of course need to either build the program as part of the android distribution itself or import the class-framework by a method explained elsewhere on the Internet.
All of this is currently in an app under production.