Xamarin Android Library Binding - Class does not contain a definition - c#

Xamarin Play Core (the package for reviews & tasks needed to launch reviews) split for v2.0.0 into individual packages, so I'm trying to create a Xamarin Android bindings library for the review and tasks. I successfully got tasks working but I am getting this error for the review nuget when it should just work according to their docs. It might be a simple fix, I thought I just had to add these lines in the metadata file but that didn't fix it:
<attr path="/api/package[#name='com.google.android.play.core.review']/class[#name='IReviewManager']" name="extends">Java.Lang.Object</attr>
<attr path="/api/package[#name='com.google.android.play.core.review.testing']/class[#name='FakeReviewManager']" name="extends">Java.Lang.Object</attr>
Here's the error I get:
...PlayCoreUpdateTest/PlayCoreUpdateTest.Android/InAppReviewService.cs(35,35): Error CS1061: 'FakeReviewManager' does not contain a definition for 'LaunchReviewFlow' and no accessible extension method 'LaunchReviewFlow' accepting a first argument of type 'FakeReviewManager' could be found (are you missing a using directive or an assembly reference?) (CS1061) (PlayCoreUpdateTest.Android)
I know the magic happens in the generated api.xml file, so here's a code dump of it. In there I do see the FakeReviewManager, but I don't see the RequestReviewFlow, when it should be there
It's still a work in progress but those are the only remaining issues, here's the GitHub code.
I watched Jonathan Dick's video on creating Xamarin library bindings and tried the Microsoft FAQ options here too
I know my functions in InAppReviewService.cs are correct because that's what the official docs tell us to use, and it's what we were using before for v1.10.
Update: I did notice there's an api.xml.class-parse file beside api.xml, that does contain the missing method LaunchReviewFlow inside the FakeReviewManager class. I'm trying to understand why it didn't show up in api.xml. Here's a dump for that one. I did notice that in the api.xml.class-parse file, there are these lines
return="com.google.android.play.core.tasks.Task<java.lang.Void>"
jni-return="Lcom/google/android/play/core/tasks/Task<Ljava/lang/Void;>;"
...
jni-signature="(Landroid/app/Activity;Lcom/google/android/play/core/review/ReviewInfo;)Lcom/google/android/play/core/tasks/Task;"
which that the v2.0 AAB file points to a play core tasks library even though it recommends pointing to the GMS version of Tasks
To counter that, I tried to add variations of these lines, but none of that helped:
<add-node path="/api/package[#name='com.google.android.play.core.review.testing']/class[#name='FakeReviewManager']">
<method abstract="false" deprecated="not deprecated" final="false" name="launchReviewFlow" jni-signature="(Landroid/app/Activity;Lcom/google/android/play/core/review/ReviewInfo;)Lcom/google/android/gms/tasks/Task;" bridge="false" native="false" return="com.google.android.gms.tasks.Task<java.lang.Void>" jni-return="Lcom/google/android/gms/tasks/Task<Ljava/lang/Void;>;" static="false" synchronized="false" synthetic="false" visibility="public" return-not-null="true">
<parameter name="p0" type="android.app.Activity" jni-type="Landroid/app/Activity;" not-null="true" />
<parameter name="reviewInfo" type="com.google.android.play.core.review.ReviewInfo" jni-type="Lcom/google/android/play/core/review/ReviewInfo;" not-null="true" />
</method>
<method abstract="false" deprecated="not deprecated" final="false" name="requestReviewFlow" jni-signature="()Lcom/google/android/gms/tasks/Task;" bridge="false" native="false" return="com.google.android.gms.tasks.Task<com.google.android.play.core.review.ReviewInfo>" jni-return="Lcom/google/android/gms/tasks/Task<Lcom/google/android/play/core/review/ReviewInfo;>;" static="false" synchronized="false" synthetic="false" visibility="public" return-not-null="true" />
</add-node>

Related

Xamarin run activity from other project in same solution

I have a xamarin solution with two android projects. I would like to run android activity in project1 from project2. I ‘ve seen threads related to this topic (like How to call an activity in another project?
Call activity from another project) and tried many suggested solutions but In the end I always get „Android.Content.ActivityNotFoundException: 'Unable to find explicit activity class {companyname.project2/companyname.project2.Droid.View.LoginView}; have you declared this activity in your AndroidManifest.xml?'” error. Is this possible in xamarin if yes how? Am I doing something wrong? Here is my source code:
Project1:
namespace BigAppManager {
    [Activity (MainLauncher = true, Name = "com.companyname.bigappmanager.MainActivity", Label = " Logowanie", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, NoHistory = true, LaunchMode = LaunchMode.SingleInstance)]
    public class MainActivity : MvxActivity<MainActivityViewModel> {
        protected override void OnCreate (Bundle savedInstanceState) {
            base.OnCreate (savedInstanceState);
            Xamarin.Essentials.Platform.Init (this, savedInstanceState);
            
            SetContentView (Resource.Layout.activity_main);
            Button button = FindViewById<Button> (Resource.Id.button);
            button.Click += ClickButton;
        }
        private void ClickButton (object sender, EventArgs e) {
  
            //Intent intent = new Intent("companyname.project2.Droid.View.LoginView");
            //StartActivity(intent);
            Intent intent = new Intent (Intent.ActionMain);
            intent.AddCategory (Intent.CategoryLauncher);
            // intent.SetClassName("companyname.project2", "companyname.project2.Droid.View.LoginView");
            intent.SetComponent (new ComponentName ("companyname.project2", "companyname.project2.Droid.View.LoginView"));
            StartActivity (intent);
        }
        public override void OnRequestPermissionsResult (int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults) {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult (requestCode, permissions, grantResults);
            base.OnRequestPermissionsResult (requestCode, permissions, grantResults);
        }
    }
}
Project2:
    
[Activity(Name = "companyname.project2.Droid.View.LoginView", Label = " Logowanie", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, NoHistory = true, LaunchMode = LaunchMode.SingleInstance)]
    public class LoginView : MvxActivity<LoginViewModel>
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.LoginView);
        }
    }
Project 2 android manifest intent filter:
<activity android:name="companyname.project2.Droid.View.LoginView">
<intent-filter>
<action android:name="companyname.project2.View.LoginView"></action>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
I don't think Manifests are merged by default. So if you look at the resulting AndroidManifest.xml in obj/Debug/android when building, you will probably notice that the LoginView entry is missing.
You can try adding the following NuGet package to your App project and see if that will merge the manifests: https://www.nuget.org/packages/Xamarin.Android.ManifestMerger/1.0.0-preview03
Otherwise, you will need to add the same entry manually in your Apps manifest for the LoginView.
EDIT:
Make sure you use the correct intent. This works fine for me:
var intent = new Intent(this, typeof(LoginView));

How can I use Wix Properties

I'm working with Wix v4 to create a msi package. I had the problem, that I must set a Property in a CustomAction (C#) at the beginning of the installation.
This works fine, but now I'm a little bit confused. The property can't be used in all my cases.
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
<Property Id="ANUMMER" Value="A2000-0000" />
<Binary Id='CustomActionReadConfig' SourceFile='...'/>
<InstallUISequence>
<!-- Set the property over session["ANUMMER"] = "..." -->
<Custom Action="CustomActionReadConfig" Before="AppSearch" />
</InstallUISequence>
The ini file hasn't a problem
<IniFile Id="Programm.ini" Action="createLine" Key="ANUMMER" Name="Programm.ini" Section="Programm" Value="[ANUMMER]" Directory="Dir" />
For the directory I found the follow workaround
<SetDirectory Action="SetApplicationFolder" Id="APPLICATIONFOLDER" Value="[ProgramFilesFolder]\[COMPANYNAME]\[MYPROGRAMM]\[ANUMMER]" Sequence="ui"/>
But the shortcuts can' use it and I didn't find a workaround
<Shortcut Id="DesktopShortcut" Directory="DesktopFolder" Name="Programm [ANUMMER]" WorkingDirectory="Dir" Advertise="yes" Icon="DesktopIcon.exe" IconIndex="0" />
<Shortcut Id="DesktopShortcut" Directory="DesktopFolder" Name="Programm" WorkingDirectory="Dir" Advertise="yes" Icon="StartMenuIcon.exe" IconIndex="0">
<ShortcutProperty Key="Name" Value="Programm [ANUMMER]"/>
</Shortcut>
Like this, I need this property in some further cases. Do I use it wrong or do I have to use an special escape combination? Can't I use properties in Name attributes? Is there an other way, to use the input as variable witch I can set in the CustomAction? Or what is the basic problem, that I can't use such a custom runtime property in sutch ways?
Thanks for help
After searching for further options I found the reason for the problem for this in an other question here: Dynamically assigning name to shortcut at run time in WIX
The property value can be used in Formatted type. I wanted to use it in LongFileNameType (Simple Type) or in strings.
If someone knows a way, to fill a variable at runtime to solve this problem, it would be nice to share it with us.
Info: The value could also be a localization variable with the format !(loc.VARIABLE).

Write Properties (name=value) to a file from an MSBuild project

For an MSBuild project, I would like to output some kind of a .config file that would be redistributed along the generated binary so the parameters used at build time can be checked by the users of the binary, programmatically.
Output file format:
PropertyName1=ValueA
PropertyName2=ValueB
...
Ideally, the list of properties to write would contain just their names. Maybe like:
<ItemGroup>
<MyExposedDictionary Include="Configuration" />
<MyExposedDictionary Include="Platform" />
<MyExposedDictionary Include="PropertyName1" />
...
</ItemGroup>
With MyExposedDictionary being the argument to give to some DotConfigFileWriter task, as well as the path of the destination file.
I found several ways to write down values to a file, including a sub-target with some C# code in it, but I'm new to MSBuild and I'm not sure how I can merge those requirements into a single Target to make it re-usable.
In case someone comes here with the same requirement, here is what I ended up with. Not really happy with the result as I was hoping for something more generic but at least it does the job and blends well in my project:
<Target Name="WriteBuildProperties" BeforeTargets="PreBuildEvent">
<WriteLinesToFile File="$(DotConfigFile)" Overwrite="true" Lines="" />
<WriteLinesToFile File="$(DotConfigFile)" Lines="ProjectName=$(ProjectName)" />
<WriteLinesToFile File="$(DotConfigFile)" Lines="Configuration=$(Configuration)" />
...
</Target>
If someone happen to have a more elegant solution, please jump in!
I am not sure where your problem is located. I have a similar requirement that a file is created by the program which just was compiled. I edited the properties of the project: in the build events enter a Post-build action like
REM create special file
"$(ProjectDir)$(OutDir)MyProgram.exe" /WriteFile MyFile.xml
Of course, you must also change your program such that it does the right thing when called with that parameter (and stops after having completed that action - does not show a GUI or start as a Windows Service).

VS2012 says "The configProtectionProvider attribute is not allowed" for ConnectionStrings section

Even though this page shows the attribute right in the tag, when I try to code it, I get the dreaded blue squiggly under the line, and the hover message is as I put in the title of this question. What do I need to do in order to activate this feature, since Microsoft's pages clearly show it being done this way.
Thanks,
Peter
I think configProtectionProvider attribute is only supported in .NET 2.0. You can use it by adding the following
xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"
to your Configuration node like this:
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"

Registering generic types and services with Castle Windsor IoC

Hello again stackoverflowians,
I thought it was about time that I learnt how to use a DI framework. I've heard a lot of good things about Castle Windsor so I decided to go with that. Now there are PLENTY of tutorials out there on how to use it, however, I cannot find much useful information about what to do when Generics get involved. Here is my issue.
I have a BaseDAO
namespace Utilities.DataAccess
{
public class BaseDAO<T> : IBaseDAO<T>
{
public BaseDAO(IConnectionProvider _connectionProvider)
{
// Stuff
}
}
}
Im a little bit new to generics in this context and I have seen some tutorials which have a 'BaseDAO' with no generic declaration and simply the interface it implements with the generics on it. I have used the above way of doing things on many previous projects (without IoC) and its worked fine for me...anyways, onwards to the App.config !
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"></section>
</configSections>
<castle>
<components>
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1, Utilities.DataAccess"
type="Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess" />
<component
id="NHibernateConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.NHibernateConnection" />
<component
id="XMLConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.XMLConnection, Utilities" />
</components>
</castle>
</configuration>
Now as some of you may of figured by now, this is a utility library. I intend to use this assembly for each project I create so that I don't have to write the same data access code which remains the same across all solutions. The implications of such of course is that I cannot tell castle exactly what type parameter I will pass to the BaseDAO, in one project it might be a Customer object, another entirely different. I have read on other forums that this is entirely possible as when you request the object from the container you can specify the type then like;
BaseDAO<Customer> baseDao = container.Resolve<BaseDAO<Customer>>();
Although it is against my design efforts, I have tried to use the following notation in the App.config
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtills.DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtils.DataAccess" />
However, this has not worked either, in any case I get the following error:
Utilities.Testing.DataAccess.Unit.Testing_BaseDAO (TestFixtureSetUp):
System.Exception : The type name Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess could not be located.
----> System.IO.FileNotFoundException : Could not load file or assembly 'Utilities.DataAccess' or one of its dependencies. The system cannot find the file specified.
Reading this error, I think it could be one of two things:
I am missing something from the config file to do with the generics of the types and services.
I have named something incorrectly I.E an assembly name.
I have treated the assembly name as the project that item is contained within, in other words, at no point have i used <solution name>.<project name>.<item folder>.<item name> but merely started at the project level...I assume that any config option would know what solution it is being called from.
Thank you for any help you may be able to give on this subject.
The assembly name can be found in Visual Studio thus:
In the solution explorer, double-click the properties node
Open the Application tab
Assembly name is near the top right corner
Or, if you're compiling at the command line, you use the /out argument.
Also, you need to specify the assembly for the type arguments (inside the square brackets). So, assuming all your types are in the DataAccess assembly, and that the assembly is called (for brevity's sake) "DataAccess":
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess" />
But I agree with other commenters that it's better to do the registrations in code. You don't have to use the verbose type syntax, for one, and you get compiler checking of your types. There are some disadvantages, however: it's harder to tell if you have unused types because the registration call counts as using the type.

Categories