I have a library project and different sub-projects with images/teksts etc, that use this library. I want every app (sub-project) to have it's own crashreport formkey, but I can only set it once, statically in the library's Application class, using "#ReportsCrashes(formKey=..."
Is there another way to set it up, so the formkey can differ for every app I create using this library?
Found the solution. You'll need the very latest version of Acra, and do exactly this:
#ReportsCrashes(formKey = "")
public class RootApplication extends Application {
#Override
public void onCreate() {
ACRA.getConfig().setFormKey(
getResources().getString(R.string.acra_form_key));
ACRA.init(this);
ACRA.getErrorReporter().setReportSender(new HockeySender());
super.onCreate();
}
}
Of course you only use a hockeysender when you use hockeyapp.
Related
Trying to integrate the AppsFlyer SDK for Android, I've followed all the steps indicated in the AppsFlyer guide. Initially, the dependency that was stated is:
implementation 'com.appsflyer:af-android-sdk:4+#aar'
But for some reason, it wasn't pointing to the latest version on it's own, making the init() version not visible. And so I instead went ahead and adjusted it to version 4.8.15 (currently the latest version), which worked as expected in the guide.
After adding the required permissions (with the optional permission) and the BroadcastReceiver (I don't have any other receivers for the referrer so I only used the SingleInstallBroadcastReceiver), I implemented the initialization on the app's Application class like so:
public class MyApp extends Application {
private static final String AF_DEV_KEY = "DEV_KEY_FROM_CONSOLE_HERE";
#Override
public void onCreate() {
super.onCreate()
initAppsFlyer();
}
public void initAppsFlyer() {
final AppsFlyerConversionListener listener = new AppsFlyerConversionListener() {
#Override
public void onInstallConversionDataLoaded(Map<String, String> conversionData) {
}
#Override
public void onInstallConversionFailure(String errorMessage) {
}
#Override
public void onAppOpenAttribution(Map<String, String> attributionData) {
}
#Override
public void onAttributionFailure(String errorMessage) {
}
};
AppsFlyerLib.getInstance().init(AF_DEV_KEY, listener, this);
AppsFlyerLib.getInstance().startTracking(this);
}
}
The manifest is pointing to the MyApp application class for sure. So that's it. The initial setup is complete. Time for the SDK Integration test as per the guide.
So I installed the app directly from Android Studio to my device, downloaded SDK Integration test app, whitelisted the device, and selected the name of the app as mentioned in the test guide. Every step followed accordingly.
Clicked on SDK Integration Testing...
Checking configuration...
Testing your app..
*app opens*
*closes*
*opens again*
Testing your app..
Checking configuration...
..
X Oops..
This app can not be monitored. Please make sure that:
You are using a supported AppsFlyer SDK version.
AppsFyler's BroadcastReceiver is configured.
startTracking() is placed in the MainActivity
It's the latest version. So it should work.
Copy pasted the receiver. Tried removing it and then re-run the test, it showed the missing receiver error. Pasted it back in.
I'm calling startTracking() in the actual application class. But what the heck. I gave it a try, called it in the MainActivity.onCreate() same result.
I have no idea what is causing the failure in the test. Not much to go on from as well since there's no details on how to debug it further. However, I checked the Dashboard, and there it is. Non-Organic install data counted.
Now I'm confused. Is there an issue with the integration or with the SDK integration test app?
We have a shared library that contains version info and is referenced by all our projects in our Visual Studio Solution.
For the most part, we can reference the version string from every project and the dll reflect the info accordingly.
My issue here is, with our Android application (xamarin based). It has a manifest file which contains the versionName and versionCode.
How can we make those values in our android manifest file read from our shared project?
My understanding is that, it is not possible. Because
The manifest file presents essential information about your app to the Android system, information the system must have before it can run any of the app's code.
From Google's documentation
So this is a file that is required before the App builds.
C# Code in Shared Project (SAP/PCL) is ready to be used only after successful Compilation. So logically setting the Version Code and Version Name in Android Manifest File from Shared logic is not possible.
Another standard approach would be to set it from String Resource (XML) file in Android. You may have to copy and paste the value from Shared Project to strings.xml file and refer it in manifest, like
#string/versionCode
Note: I do not know anything about xamarin.
In java you can get the versioninfo from the manifest like this
public static String getAppVersionName(final Context context) {
try {
final String versionName = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0).versionName;
return versionName;
} catch (final NameNotFoundException e) {
}
return null;
}
I assume that xamarin has some mechanism to call PackageManager to get Packageinfo, too
You could do this by using a Dependency Service. Here's a great article on them: https://developer.xamarin.com/guides/xamarin-forms/dependency-service/
The idea would be your Dependency Service would expose the Android specific information to the shared code library.
For instance you might have an interface in your common code declared such as:
public interface IPlatformVersionInfo
{
string GetOSVersion ();
}
Now, in your Android library you would implement it:
public class PlatformVersionInfo : IPlatformVersionInfo
{
public string GetOSVersion () {
return Android.OS.Build.VERSION.SdkInt.ToString ();
}
}
Finally, in your common code you would use your dependency service of choice to invoke an instance of it:
var osVersion = DependencyService.Get<IPlatformVersionInfo>().GetOSVersion ();
Of course this is somewhat pseudo-code and depending what dependency service you choose the code may look a bit different.
I'm making an app where I have to have in app purchases (buying keys that I can further use in the app).
I have looked at this component http://components.xamarin.com/view/xamarin.inappbilling, but I have no idea how I can implement this in xamarin forms. Is there anyone out there willing to help me with this problem? Is there any open source projects with in app purchase that I can look at?
I know its late, but this might help someone:
The way to do achieve this is to create a service and then surface it to a standard interface (as per your requirement) that will be consumed within the forms project.
You can even use MessagingCenter to communicate between Android and Xamarin.Forms project.
FormsPrject:
MessagingCenter.Send<MainPage, string>(this, "BuyProduct", "buyButtonPressed");
AndroidPoject
MessagingCenter.Subscribe<MainPage, string>(this, "BuyProduct", (sender, arg) =>
{
//logic to buy product
}
Hope that helps!!
The question is very vague so I will offer a general answer and some notes that I found important. I am using Visual Studio 2015 with Xamarin Forms 2.3.0.107.
I would use abstraction for this instead of sending messages directly between the projects.
The basic idea is, you will create a public interface in your Xamarin Forms project. Since your Andriod project has a reference to the Xamarin Forms project, it can use this public interface. Then you will implement this interface in your Android project will all of the billing logic. In the Xamarin Forms project. Using the Dependency service we can get the existing instance of the implementation into the Xamarin Forms project. Then, you can code against the interface. This is especially useful if you ever want to do an iPhone or other implementation, because you would never need to make changes to the Xamarin Forms code; you can just plug in new implementations.
It might be a bit out of scope but, be sure to meet all of the Google requirements as far as setting up your developer account and your merchant account and your API account. It is all very confusing and messy.
The Xamarin component in nuget is currently version 1.5. However, the component has a newer published version. You want to use the newer (2.0 or higher) version.
Use the Android SDK manager to install the Google Play Billing Library.
In your Android project, add a reference to Xamarin.InAppBilling and add a Xamarin.InAppBilling component.
The Google object has to live in an Android activity, because you depend on overriding an activity method to complete purchases (I used the MainActivity here and made the google object a static for easy access)
Testing this with Google Play is a hassle. The documentation is confusing because of differences between versions. You cannot use actual product id's until you publish your app. They provide test id's that can be used during testing but they only offer some functionality.
I have made these code examples as minimal as possible to illustrate the concept. You will obviously want to do much more.
Xamarin Forms project
Create an interface:
public interface IInAppBilling
{
void Pay(string productId);
}
Any time you want to use the billing service, you use IInAppBilling billingService = DependencyService.Get<IInAppBilling>(); to get a reference to the device-specific (Android) implementation.
//call this from a button click or whatever
void BuySomething(string somethingId)
{
//Get any IInAppBilling object that is registered with the DependencyService.
IInAppBilling billingService = DependencyService.Get<IInAppBilling>();
billingService.Pay(somethingId);
}
Android Project
Override an activity's OnCreate method and create an InAppBillingServiceConnection:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
public static InAppBillingServiceConnection google;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
google = new InAppBillingServiceConnection(this, "MII...ApplicationKey");
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
}
Create a class that implements the Xamarin Forms interface we created earlier. It is important not to ignore the assembly: Dependencyannotation at the top. This is what makes the class available to the Dependency service in the Xamarin Forms object:
[assembly: Dependency(typeof(com.myapp.InAppBilling))]
namespace com.myapp
{
class InAppBilling :IInAppBilling
{
public void Pay(string productId)
{
MainActivity.google.BillingHandler.BuyProduct(productId, ItemType.Product, "MyUniquePayload");
}
}
}
Override the activity's OnActivityResult method to finalize purchases:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
// Ask the open service connection's billing handler to process this request
try
{
google.BillingHandler.HandleActivityResult(requestCode, resultCode, data);
}
catch (Exception ex)
{
//log it or something?
}
}
In my Java code, I use the Debug flag to control debug model, if is debug ,there are some extra functions,such as:sway the phone show a activity to change app version. Now I want to erase these code when publishing the code to market.
Like the code below, is there a way to make VersionSwitchService.class code is null and other code is running normal?
I mean that even if, someone decompiles the apk, VersionSwitchService.class code is seen as blank.
if (isDEBUG) {
VersionSwitchService.libStart(this, new LibVersionSwitch() {
#Override
public void versionSwitchToOnline() {
//...
}
#Override
public void versionSwitch(String version) {
//...
}
});
}
If you make isDebug final static:
final static boolean isDebug = false;
the Java compiler will complete remove the parts of code that are unreached. Sp in your example, the 'then'-part is completely omitted and thus not available in your apk.
Furthermore, when creating a (release) apk build, the Android tools will strip all methods and classes that are unused. So, if your VersionSwitchService class is only used for debugging, it will not present (due to the combination of the static final debug constant)
In Android I get the version of the SDK easily (Build.VERSION.SDK) but I need to use LabeledIntent only if the platform is newer than 1.6 (>Build.VERSION_CODES.DONUT)
I suppose that Reflection is necessary (I have read this link but it is not clear for a class or to me).
This is the code but it gives me an exception because in my Android 1.6, the compiler verifies if the package exists even if the condition is not applied:
Intent theIntent=....;
if(Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.DONUT)
{
try{
Intent intentChooser = Intent.createChooser(intent,"Choose between these programs");
Parcelable[] parcelable = new Parcelable[1];
parcelable[0] = new android.content.pm.LabeledIntent(theIntent, "", "Texto plano", 0);
intentChooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, parcelable);
activity.startActivity(intentChooser);
}
catch(Exception e)
{
activity.startActivity(theIntent);
}
} else
{
activity.startActivity(intentMedicamento);
}
HOW I SOLVED IT, SOME NOTES TO THE RIGHT ANSWER
#Commonsware show me the way to do it. We create a bridge class so that depending on the API LEVEL, you instance one class that uses an API LEVEL or another class that uses another API LEVEL.
The only detail one beginner could forget is that you have to compile your app with the newest SDK you are goint to make reference.
public abstract class LabeledIntentBridge {
public abstract Intent BuildLabeledIntent(String URL, Intent theintent);
public static final LabeledIntentBridge INSTANCE=buildBridge();
private static LabeledIntentBridge buildBridge() {
int sdk=new Integer(Build.VERSION.SDK).intValue();
if (sdk<5) {
return(new LabeledIntentOld());
}
return(new LabeledIntentNew());
}
}
So in the LabeledIntentNew, I included all the code that refers to LabeledIntent only available in API LEVEL 5. In LabeledIntentOld, I can implement another kind of control, in my case I return the intent itself without doing nothing more.
The call to this class is done like this:
LabeledIntentBridge.INSTANCE.BuildLabeledIntent(URLtest,theIntent);
Follow the wrapper class pattern documented in the page you linked to above.
You have to use reflection...
The idea is good, but in your code you refer to LabeledIntent which is not available in 1.6. So when your app runs against 1.6 devices, it cannot find the class and crashes.
So the idea is to write code where you don't refer to LabeledIntent when running in 1.6. To do this, you can write a wrapper class (LabeledIntentWrapper) which extends LabeledIntent and call it in your function. So, in 1.6, the device will see a reference to a known class: LabeledIntentWrapper.