PeripheralManagerService throws NoClassDefFoundError - android-things

I have the following code in my app to access PeripheralManagerService:
PeripheralManagerService service = new PeripheralManagerService();
Gpio ledGpio;
try {
ledGpio = service.openGpio("BCM6");
ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
} catch (IOException e) {
Log.e(TAG, "Error configuring GPIO pins", e);
}
After updating to the latest Android Things (Developer Preview 7), my app is now throwing
a NoClassDefFoundError:
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/things/pio/PeripheralManagerService;
...
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.android.things.pio.PeripheralManagerService" on path: DexPathList[...]
This code was working before, why has this started happening after the update?

Starting in Preview 7, Android Things API services are not constructed as new
instances. They are instead accessed as singletons via getInstance() to be
more in line with Android API paradigms. Some of the classes, such as
PeripheralManagerService were also renamed.
Be sure to update your app to use the Preview 7 SDK:
dependencies {
compileOnly 'com.google.android.things:androidthings:0.7-devpreview'
}
Then modify your code to access the PeripheralManager instead:
PeripheralManager manager = PeripheralManager.getInstance();
Gpio ledGpio;
try {
ledGpio = manager.openGpio("BCM6");
ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
} catch (IOException e) {
Log.e(TAG, "Error configuring GPIO pins", e);
}
Review the Android Things API reference
to verify if any of the other APIs you are calling have changed.

Rather than using PeripheralManagerService service = new PeripheralManagerService(); use
PeripheralManager peripheralManager=PeripheralManager.getInstance();

I ran into the same issue but the above solution did not work for me. I was trying to create a alphanumeric display project by choosing new->project and choosing Android Things. The generated gradle build file looked like below. Note the driver for ht16k33 has version 0.3. This caused the problem. Once I changed it to 1.0 the ClassNotFound issue went away.
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.android.things.contrib:driver-ht16k33:0.3'
implementation 'com.android.support:support-v4:28.0.0-beta01'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
compileOnly 'com.google.android.things:androidthings:+'
}

Related

MvvmCross 4.4.0, MvxAndroidBindingContextHelpers.Current() is Null when targeting API Level 31 and running on Android 12

Our Xamarin Android app relies heavily on some older components in MvvmCross 4.4.0 and so has not been updated to modern versions.
We used the guide found here to modernise just enough to get over the API 29/Android 10 hurdle:
https://blog.ostebaronen.dk/2020/08/old-mvvmcross-and-android-10.html
We're now at the API 31/Android 12 hurdle and, whilst everything builds and executes fine with API 31 when running on Android 11 and below, Android 12 is crashing.
The MainActivity is initialising with a null ViewModel because the LayoutInflater (already corrected for API 29) cannot retrieve the current binding context with MvxAndroidBindingContextHelpers.Current().
Nothing in the Android 12 behaviour changes guides gives an indication as to what is causing this change. We have also reviewed changes in modern versions of the MvvmCross.Binding source and can't see any obvious changes that correct this behaviour.
This is the code in LayoutInflater.cs where the problem first surfaces:
public override View? Inflate(int resource, ViewGroup? root, bool attachToRoot)
{
// Make sure our private factory is set since LayoutInflater > Honeycomb
// uses a private factory.
SetPrivateFactoryInternal();
// Save the old factory in case we are recursing because of an MvxAdapter etc.
IMvxLayoutInflaterHolderFactory? originalFactory = _bindingVisitor.Factory;
try
{
IMvxLayoutInflaterHolderFactory? factory = null;
// Get the current binding context
var currentBindingContext = MvxAndroidBindingContextHelpers.Current();
// currentBindingContext is null on Android 12, not on Android 11 and below
if (currentBindingContext != null)
{
factory = FactoryFactory?.Create(currentBindingContext.DataContext);
// Set the current factory used to generate bindings
if (factory != null)
_bindingVisitor.Factory = factory;
}
// Inflate the resource
var view = base.Inflate(resource, root, attachToRoot);
// Register bindings with clear key
if (currentBindingContext != null)
{
if (factory != null)
currentBindingContext.RegisterBindingsWithClearKey(view, factory.CreatedBindings);
}
return view;
}
finally
{
_bindingVisitor.Factory = originalFactory;
}
}
Any insight as to potential causes of the problem would be welcome, even if it's a concrete reason why MvvmCross 4.4.0 is simply no-longer viable on Android 12.
Thanks very much.
Update: We have now successfully updated to MvvmCross 5.0.1 and the problem still remains (which we expected). Our dependency is on MvvmCross.Droid.Shared, which is removed from newer versions. Can anybody recommend a guide on migrating away from MvvmCross.Droid.Shared please, as it doesn't appear to be mentioned in the upgrade guides other than to just remove it?
Update 2: Switching out the LayoutInflater for the one from MvvmCross 9.0.1 makes no difference. We've done this simply to rule that out. The issue feels like it related more to Binding.
The issue was not directly related to MvvmCross, but rather a change in Android 12 behaviour that prevented initialisation in a manner that meant ViewModel binding wasn't happening despite the rest of the code executing.
The resolution was to add some specific AndroidX initialisation lines to the AndroidManifest:
<provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup">
<meta-data android:name="androidx.lifecycle.ProcessLifecycleInitializer" android:value="androidx.startup" />
</provider>
...and to
Update Xamarin.GooglePlayServices NuGet packages
Add Xamarin.AndroidX NuGet packages
Increase the minSdkVersion from 19 to 21

Error when asking for Location using expo-location

I've beeing using expo-location since the beginning of my project, and didn't have any problem with this library.
And it is implemented as follow:
import * as Location from 'expo-location';
let { status } = await Location.getForegroundPermissionsAsync();
console.log('STATUS', status);
if (status === 'granted' && !getLocationPermissionStatus) {
setLocationPermissionStatus('granted');
}
But since today, when I've changed my machine and downloaded my project and setup everything again, the project is throwing this error when the notification is called.
Error: Permissions module not found. Are you sure that Expo modules are properly linked? checkPermissions$#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:460494:32
I'd like some help on this issue.
ps.: I've expo-notifications being called on the same block of code and its not causing any issue.

What is the best way to implement firebase crash report in iOS swift 3

Here incase of android firebase crash can be implemented in APPLICATION class like.. below example
(...here, if android app is crashed this overrriden method uncaughtException(Thread thread, Throwable e) is called where we report crash to firebase...)
So, I want to know if there is any better way to implement firebase crash in iOS swift 3 like this.
/** onCreate method of MainApplication.java */
#Override
public void onCreate() {
super.onCreate();
reportFirebaseCrash();
}
/** Report FirebaseCrash Exception if application crashed */
private void reportFirebaseCrash() {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable e) {
AppUtils.showLog(TAG, "reportFirebaseCrash");
FirebaseCrash.report(e);
}
});
}
Highly recommend you check out the Firebase docs — they're quite well done and should give you all the help you need to get started.
In particular, the simplest way to get up and running is to use the crash reporting pod:
pod 'Firebase/Crash'
Then you need to configure a FIRApp shared instance. Once that's set up (or if you have already), you need to configure your build system to upload crash reports. The docs link includes all the necessary details to do it, but tl;dr, you need to create a new Run Script build phase:
# Replace this with the GOOGLE_APP_ID from your GoogleService-Info.plist file
GOOGLE_APP_ID=1:my:app:id
# Replace the /Path/To/ServiceAccount.json with the path to the key you just downloaded
"${PODS_ROOT}"/FirebaseCrash/upload-sym "/Path/To/ServiceAccount.json"
Firebase also supports Bitcode in order to gather crash data from production users.

iOS Asynchronous Unit Testing (waitForExpectations failing) in Xcode 8 / Swift 3

I'm updating my Cocoapod that I developed to use Swift 3. Before I upgraded, all of my asynchronous unit tests were working perfectly fine. But now after upgrading, every single one of them immediately fail and I have no idea why. Here is what each one is structured like:
override func setUp() {
super.setUp()
validationExpectation = expectation(description: "Validation")
}
.
.
.
func testSymbolRequest(){
_ = MyCocoapod.makeSymbolRequest(symbol: "ABC", success: { (symbolObject) in
self.validationExpectation.fulfill()
XCTAssert(true)
}) { (error) in
self.validationExpectation.fulfill()
XCTFail(error.description)
}
waitForRequestToFinish()
}
.
.
.
func waitForRequestToFinish(){
waitForExpectations(timeout: 60.0) { (error) in
if let error = error {
XCTFail(error.localizedDescription)
}
}
}
The waitForExpectations function isn't waiting at all. It immediately fails after being called. I have also confirmed that is has nothing to do with my actual networking code and the requests work perfectly fine in my Cocoapod example project. I'm using Alamofire. I don't think that's the problem but I thought it might be worth mentioning. The error message that is printed out is "unknown error".
If you are trying to test your CocoaPod that you are developing, for some reason, the default testing target that it creates makes the waitForExpectations() function not work properly for that particular testing target. I was able to get it to finally work by doing these steps in order:
Delete the current testing target
Create a new testing target
Run a pod install and make sure the pod file is updated accordingly
Following these steps, I was able to get the waitForExpectations() to finally work within my network requests.

The Type initializer for 'Realms.Realm' threw an exception

I am trying to implement Realm on a smaller Xamarin/Mvvmcross/iOS/Droid project in order to test it's ability to replace SQLite.
I have it working well on the iOS project but am getting exceptions on the Droid project when attempting to call Realm.GetInstance();
The Type initializer for 'Realms.Realm' threw an exception
Inner Exception
System.Reflection.ReflectionTypeLoadException
The classes in the module cannot be loaded.
I have narrowed it what I believe is an issue with reflection if the MvvmCross setup occurs before the Realm dll is loaded.
For example if I call Realm.GetInstance() in any activity that inherits from MvxActivity or MvxAppCompatActivity (or anywhere in the Mvvmcross Setup / CreateApp process) the exception occurs.
If however I call var db = Realm.GetInstance() (& db.Close()) from a normal Droid Activity first, and then start the Mvx Setup process, by starting an MvxActivity, from the Droid Activity it works fine, and continues to work through the application lifecycle.
Likewise if I subclass Application and open a Realm instance in OnCreate() and close it Real will initialise anywhere else in the application.
sample code
//works
[Application]
public class CustomApplication : Application
{
public CustomApplication (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer)
{
}
public override void OnCreate ()
{
base.OnCreate ();
var db = Realm.GetInstance ();
db.Close ();
}
}
//does not work unless Realm.GetInstance() has already been called once
[Activity(Label = "View for FirstViewModel")]
public class FirstView : MvxActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.FirstView);
var db = Realm.GetInstance ();
db.Close ();
}
}
I've put a test project on github at https://github.com/vurtigo/TestRealm
This is an unfortunate mix-up between Realm and Xamarin Android.
The static constructor on the Realm class walks through all the assemblies in the current AppDomain to discover all the types that inherit from RealmObject. However, if at the time Xamarin Android builds Java binding code this will define a new System.Reflection.Emit.AssemblyBuilder assembly that will raise a TypeLoadException when its types are enumerated (see Bug 39679 - ReflectionTypeLoadException after some reflection stuff).
The workaround is to cause the Realm static constructor to be invoked before any of the MvvmCross code causes Xamarin Android to emit binding code. You can do that by accessing any of the static members on Realm such as ReferenceEquals or even by including it in a typeof(Realm) expression. I suppose MvxApplication.Initialize() is a good place to do it.
In any case, I have proposed a fix that will ignore AssemblyBuilder instances in general. The very next Realm release should include it and you'll be able to delete the workaround code as soon as you upgrade.

Resources