Xamarin, Android, PCL SQLLite, SQLite.NET snafu - android

It's pretty hard to understand the nuget packages to install in a Xamrin solution when searching around the web, there are dozens of packages, dozens of different solutions.
Right now, our solution has 2 projects, an Android one and a PCL one. Our model and data access is defined in the PCL. Our platform implementation is defined in the Android one.
We need SQLite, SQLite.Net (for the data annotations and table relations), and SQLiteExtentions for the *withchildren methods.
We are stuck in old versions because anytime we try to update anything, our frail magical way in which our installed packages are working together just falls apart. We do need to upgrade or find a way to add SQLCipher to this weird snafu of nuget packages.
Our current packages installed, which works:
Android project
Mono.Data.Sqlite.Portable 1.0.3.5 (not sure why...)
SQLite.Net.Core-PCL 3.1.1
SQLite.Net.Platform.XamarinAndroidN 3.1.1
SQLite.Net-PCL 3.1.1
SQLiteNetExtensions 1.3.0 (required for GetWithChildren etc.)
SQLitePCL.raw 0.9.3
PCL Project (model definition and data access methods)
Mono.Data.Sqlite.Portable 1.0.3.5 (not sure why...)
SQLite.Net.Core-PCL 3.1.1
SQLite.Net.Platform.XamarinAndroidN 3.1.1
SQLite.Net-PCL 3.1.1
SQLiteNetExtensions 1.3.0 (required for GetWithChildren etc.)
SQLitePCL.raw 0.9.3
Currently, if we update the SQLiteExtensions to 2.0, a bunch of other SQLite nuget packages are installed, breaking the frail stability of our data access code (fails on the *WithChildren methods with:
Severity Code Description Project File Line Suppression State
Error CS1929 'SQLiteConnection' does not contain a definition for
'GetWithChildren' and the best extension method overload
'ReadOperations.GetWithChildren<TEntity>(SQLiteConnection, object, bool)'
requires a receiver of type 'SQLiteConnection'
We'd also need to incorporate SQLiteCipher and no combinations of packages can be made to work with our solution.
Our Android platform specific implementation:
#region Usings
using OURPCLLib.DataAccess;
using Serilog;
using SQLite.Net;
using SQLite.Net.Interop;
using SQLite.Net.Platform.XamarinAndroid;
using System;
using System.IO;
#endregion Usings
public class AndroidSQLiteDatabase : SQLiteDatabaseAccess
{
protected ISQLitePlatform SQLitePlatform
{
get { return new SQLitePlatformAndroidN(); }
}
protected override SQLiteConnection GetConnection()
{
var conn = new SQLiteConnection(
SQLitePlatform,
"dbpathforus.sqlite",
SQLiteOpenFlags.ReadWrite |
SQLiteOpenFlags.FullMutex |
SQLiteOpenFlags.ProtectionCompleteUnlessOpen |
SQLiteOpenFlags.Create |
SQLiteOpenFlags.SharedCache);
return conn;
}
}
The (simplified) base data access class in the PCL:
#region Usings
using OURPCLLib.DataAccess.Entities;
using SQLite.Net;
using SQLite.Net.Attributes;
using SQLite.Net.Interop;
using SQLiteNetExtensions.Extensions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
#endregion Usings
public abstract class SQLiteDatabaseAccess
{
protected abstract SQLiteConnection GetConnection();
// Example of one of the many methods accessing the DB using SQLite.Net
public bool Any<TEntity>(Expression<Func<TEntity, bool>> expression)
where TEntity : class, IBaseEntity, new()
{
using (var currentConnection = this.GetConnection())
{
return currentConnection.Table<TEntity>().Where(expression).FirstOrDefault() != null;
}
}
// Example of one of the methods accessing the DB using SQLiteExtentions
public TEntity GetWithChildren<TEntity>(int id, bool recursive = false)
where TEntity : class, IBaseEntity, new()
{
using (var currentConnection = this.GetConnection())
{
return currentConnection.GetWithChildren<TEntity>(id, recursive);
}
}
}
Anyone can help us as to how to use SQLite with SQLIte.net, SQLiteExtentions and SQLIte cipher on a project like ours? (data access in a pcl and connection implementation in an android project?

For anyone wondering, I solved it, with minimal code impact, and some loss of functionality but not much, by only installing SQLiteNetExtensions and letting it get its SQLite dependency by itself.

Related

Kotlin Mutliplatform : Maping Swift/Objc code to Kotlin in iOSMain module?

I am learning KMM. I am now designing a common Location fetching in iOSMain and Android main
My problem is , I don't know to map Swift to Kotlin in iOSMain
For example,
The Swift code for , getting location is
var locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
var currentLoc: CLLocation!
if(CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways) {
currentLoc = locationManager.location
print(currentLoc.coordinate.latitude)
print(currentLoc.coordinate.longitude)
}
Kotlin side implementation:
In the above code:
How to use the Swift's .authorizedWhenInUse and .authorizedAlways in Kotlin Code ?
And the in currentLoc.coordinate.longitude , the longitude and latitude is not resolving . Why ?
Please help me
Mapping Swift (Objective-C) to Kotlin
How to use the Swift's .authorizedWhenInUse and .authorizedAlways in Kotlin Code ?
According to Kotlin's documentation on interoperability, Kotlin/Native provides bidirectional interoperability with Objective-C, not Swift, so my first recommendation would be to reference Apple's Objective-C documentation over the Swift documentation.
If you pull up the Swift documentation for .authorizedWhenInUse, you'll see you can switch the language to Objective-C:
Switch this to the Objective-C documentation to see how to reference this in Objective-C:
Given this, you should be able to use kCLAuthorizationStatusAuthorizedWhenInUse in your Kotlin code.
Referencing iOS Frameworks
Since you already have some reference code, you could also simply Command+Click (or Command+B) one of the objects (for example, CLLocationManager) which should open up the compiled Kotlin code.
Manually you can also access all iOS frameworks from the "Project" View of Android Studio → "External Libraries" and then search for the iOS framework that you are searching for.
Here, you can dig through the frameworks to find what you're looking for. Not knowing the equivalent Objective-C API, you could just search for "authorizedWhenInUse" and can find it:
Dealing with C-structs
currentLoc.coordinate.longitude , the longitude and latitude is not resolving
This is more complicated...
The location property is of type CLLocationCoordinate2D and (the important part!) is that it is contained within a CValue:
#kotlinx.cinterop.ExternalObjCClass public open class CLLocation : platform.darwin.NSObject, platform.Foundation.NSCopyingProtocol, platform.Foundation.NSSecureCodingProtocol {
...
public final val coordinate: kotlinx.cinterop.CValue<platform.CoreLocation.CLLocationCoordinate2D> /* compiled code */
Note that in Objective-C, CLLocationCoordinate2D is a C struct:
typedef struct CLLocationCoordinate2D {
...
} CLLocationCoordinate2D;
The Kotlin documentation here is thin, but it shows the methods available for CValue includes the .useContents() method.
Therefore, your code could be written as follows (compiled and confirmed that this runs and generates a location on a physical device):
val locationManager = CLLocationManager()
val currentLoc: CLLocation?
if (locationManager.authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse ||
locationManager.authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
currentLoc = locationManager.location
currentLoc?.coordinate?.useContents {
println("latitude = ${latitude}")
println("longitude = ${longitude}")
}
}
[Update September 2022]
If you want to dig deeper, I also published a blog post on writing iOS-platform-dependent code using Kotlin with KMM's expect/actual: artandscienceofcoding.com/science/avoid-this-kmm-technique

Firebase not-equal queries not working on Android

I read the latest Firebase Blog which reports firebase now supports not-equal queries. However, it is not working on this android code snippet and I am getting Unresolved reference: where error when using where.
private fun getAllContacts() {
val currentUserPhoneCredential = auth.currentUser?.phoneNumber!!
firestore.collection("Contacts")
//getting unresolved reference when using where
.where("phoneNumber", "!=", currentUserPhoneCredential)
.get().addOnSuccessListener { querySnapshot ->
for (doc in querySnapshot) {
val user = doc.toObject(User::class.java)
contactsList.add(user)
contactsNames.add(user.name!!)
}
adapter.notifyDataSetChanged()
}
}
I am using the latest Firebase Android Library and running Android SDK 30.0 on Android Studio 4.0.2
implementation 'com.google.firebase:firebase-firestore:21.7.1'
Here is an image of my code
You are using the API for JavaScript, not Java. Be sure to switch to the "java" tab when viewing the documentation, and you will see that the API is whereNotEqualTo():
.whereNotEqualTo("phoneNumber", currentUserPhoneCredential)
I think you are looking for this,
https://firebase.google.com/docs/firestore/query-data/queries#not_equal
firestore.collection("Contacts").whereNotEqualTo("phoneNumber", currentUserPhoneCredential)
You are using the API of web.
Note: For iOS, Android, and Java, the comparison operator is explicitly named in the method.
citiesRef.whereEqualTo("state", "CA")
citiesRef.whereLessThan("population", 100000)
citiesRef.whereGreaterThanOrEqualTo("name", "San Francisco")
citiesRef.whereNotEqualTo("capital", false)
So for android java and android kotlin use following code
firestore.collection("Contacts").whereNotEqualTo("phoneNumber", currentUserPhoneCredential)
for more details you can refer this link

Titanium Hyperloop access to android.os.SystemProperties

I have been trying a ( i hope) simple bit of Android hyperloop code directly within a titanium project (using SDK 7.0.1.GA and hyperloop 3).
var sysProp = require('android.os.SystemProperties');
var serialNumber = sysProp.get("sys.serialnumber", "none");
But when the app is run it reports
Requested module not found:android.os.SystemProperties
I think this maybe due to the fact that when compiling the app (using the cli) it reports
hyperloop:generateSources: Skipping Hyperloop wrapper generation, no usage found ...
I have similar code in a jar and if I use this then it does work, so I am wondering why the hyperloop generation is not being triggered, as I assume that is the issue.
Sorry should have explained better.
This is the jar source that I use, the extraction of the serial number was just an example (I need access to other info manufacturer specific data as well), I wanted to see if I could replicate the JAR functionality using just hyperloop rather that including the JAR file. Guess if it's not broke don't fix it, but was curious to see if it could be done.
So with the feedback from #miga and a bit of trial and error, I have come up with a solution that works really well and will do the method reflection that is required. My new Hyperloop function is
function getData(data){
var result = false;
var Class = require("java.lang.Class");
var String = require("java.lang.String");
var c = Class.forName("android.os.SystemProperties");
var get = c.getMethod("get", String.class, String.class);
result = get.invoke(c, data, "Error");
return result;
}
Where data is a string of the system property I want.
I am using it to extract and match a serial number from a Samsung device that is a System Property call "ril.serialnumber" or "sys.serialnumber". Now I can use the above function to do what I was using the JAR file for. Just thought I'd share in case anyone else needed something similar.
It is because android.os.SystemProperties is not class you can import. Check the android documentation at https://developer.android.com/reference/android/os/package-summary.html
You could use
var build = require('android.os.Build');
console.log(build.SERIAL);
to access the serial number.

Unity Plugin AndroidJavaException NoSuchMethodError on Function with parameters

I got a very annoying issue. All of my Android plugins in Unity just work if I dont use parameters in the calling functions. I am working on this issue since 2 days and I am slowly running out of ideas. Even a minimal project doesnt work. I am sure Iam doing it right because my functions are working fine without parameters.
Unity:
void Start (){
AndroidJavaClass pluginClass = new AndroidJavaClass("tnbrtrm.lications.de.myplugin.MyPlugin");
String test = pluginClass.CallStatic<string>("getMessage", new object[] { "alalalalala" });
Debug.Log("callShareAppAARPlugin: " + test);}
Android:
public class MyPlugin extends UnityPlayerActivity {
public static String getMessage(String text)
{ return "Hello World! " + text; }
}
My plugin prints "Hello world" correctly when I delete the parameter "String text", but with parameter I get this annoying error:
AndroidJavaException: java.lang.NoSuchMethodError: no static method "Ltnbrtrm/lications/de/myplugin/MyPlugin;.getMessage(Ljava/lang/String;)Ljava/lang/String;"
I see this error using Plugins as *.jar or *.aar. And I also had a look into this packages and my Classes and Functions are there. Otherwise it wouldnt work without parameters... I tried AndroidJavaClass and AndroidJavaObject.
Can anyone please help me? I tried a lot of things... (older JDK versions, etc.) I seems so easy in all the turorials so I assume it has something to do with my system or unity (5.3.5 pro).
Kind regards,
Tino

PCL working with shared code (cross platform library)

I'm new with Xamarin and have to create a cross platform library (iOS, Android, Win Phone). i have so much difficult to create a pcl who works for those 3 platforms.
For example, this pcl needs establish a socket connection with a printer.
In pcl i can't use System.Net.Sockets so my idea is create a method and tried call his code with shared project .
when i execute the code, is stepped over the code inside #if __ANDROID__ .
PCL
public class Class1
{
public void socket()
{
Conecta.Class oi = new Conecta.Class();
oi.conecta();
}
}
Shared code
#if __ANDROID__
using System.Net.Sockets;
#endif
namespace Conecta
{
class Class
{
public void conecta()
{
#if __ANDROID__
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
clientSocket.Connect("192.168.210.171", 4002);
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes("teste \n");
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
#endif
}
}
}
It's just a test, the code isn't sophisticated
Someone can help me?
Any other idea?
I believe PCL is not yet finished.
Even if you can resolve your printer issue in future you will have a lot of other problems.
In our project we prefer to share a code from one directory with different .csproj files.
PCL benefits really not worth powder and shot.

Categories

Resources