Expose an Interface of a Class Loaded from a Framework at Runtime

Expose an interface of a class loaded from a framework at runtime

The easiest way to do dynamic Objective-C stuff is to use Objective-C.

ImageAnalyzer.h:

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface SKUIAnalyzedImageColors : NSObject

@property (nonatomic, readonly) UIColor* backgroundColor;
@property (nonatomic, readonly) BOOL isBackgroundLight;
@property (nonatomic, readonly) UIColor* textPrimaryColor;
@property (nonatomic, readonly) UIColor* textSecondaryColor;

@end

SKUIAnalyzedImageColors* _Nullable analyzeImage(UIImage* image);

NS_ASSUME_NONNULL_END

ImageAnalyzer.m:

#import "ImageColorAnalyzer.h"
#include <dlfcn.h>

static Class _SKUIImageColorAnalyzerClass;

@interface SKUIImageColorAnalyzer : NSObject
+ (SKUIAnalyzedImageColors*)analyzeImage:(UIImage*)arg1;
@end

SKUIAnalyzedImageColors* analyzeImage(UIImage* image)
{
if (!_SKUIImageColorAnalyzerClass)
{
if (!dlopen("/System/Library/PrivateFrameworks/StoreKitUI.framework/StoreKitUI", RTLD_NOW))
{
NSLog(@"No framework.");
return nil;
}
_SKUIImageColorAnalyzerClass = NSClassFromString(@"SKUIImageColorAnalyzer");
if (!_SKUIImageColorAnalyzerClass)
{
NSLog(@"No Class.");
return nil;
}
}

return [_SKUIImageColorAnalyzerClass analyzeImage:image];
}

You can then use the analyzeImage function and the SKUIAnalyzedImageColors class easily from either Swift or Objective-C code.

if let image = UIImage(named:"MyImage") {
if let colors = analyzeImage(image) {
print("Background Color: \(colors.backgroundColor)")
}
}

If you really want to do it all in Swift, first declare the parts of the SKUIAnalyzedImageColors Objective-C interface you want to use:

@objc protocol ImageColors {
var backgroundColor: UIColor { get }
var isBackgroundLight: Bool { get }
var textPrimaryColor: UIColor { get }
var textSecondaryColor: UIColor { get }
}

Then use unsafeBitCast to cast the opaque object instance to your desired Objective-C interface:

let img = UIImage(named: "someImage.jpg")!
let rawAnalyzedImageColors = function(analyzerClass, selector, img)

let analyzedImageColors = unsafeBitCast(rawAnalyzedImageColors, ImageColors.self)
print("Background color: \(analyzedImageColors.backgroundColor)")

How do I use a private iOS framework from Swift?

I found one solution which requires some manual work, but does work in pure Swift.

The trick is to create an @objc protocol in Swift which matches the Objective-C methods, then do an unsafe cast to that protocol type. In my case, the protocol looks like this:

@objc protocol UIASyntheticEvents {
static func sharedEventGenerator() -> UIASyntheticEvents

//@property(readonly) struct __IOHIDEventSystemClient *ioSystemClient; // @synthesize ioSystemClient=_ioSystemClient;
var voiceOverStyleTouchEventsEnabled: Bool { get set }
var activePointCount: UInt64 { get set }
//@property(nonatomic) CDStruct_3eca2549 *activePoints; // @synthesize activePoints=_activePoints;
var gsScreenScale: Double { get set }
var gsScreenSize: CGSize { get set }
var screenSize: CGSize { get set }
var screen: UIScreen { get set }
var onScreenRect: CGRect { get set }

func sendPinchCloseWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, inRect: CGRect)
func sendPinchOpenWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, inRect: CGRect)
func sendDragWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, withFlick: Bool, inRect: CGRect)
func sendRotate(_: CGPoint, withRadius: Double, rotation: Double, duration: Double, touchCount: UInt64)
func sendMultifingerDragWithPointArray(_: UnsafePointer<CGPoint>, numPoints: Int32, duration: Double, numFingers: Int32)
func sendPinchCloseWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendPinchOpenWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendFlickWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendDragWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
func sendTaps(_: Int, location: CGPoint, withNumberOfTouches: Int, inRect: CGRect)
func sendDoubleFingerTap(_: CGPoint)
func sendDoubleTap(_: CGPoint)
func _sendTap(_: CGPoint, withPressure: Double)
func sendTap(_: CGPoint)
func _setMajorRadiusForAllPoints(_: Double)
func _setPressureForAllPoints(_: Double)
func moveToPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64, duration: Double)
func _moveLastTouchPoint(_: CGPoint)
func liftUp(_: CGPoint)
func liftUp(_: CGPoint, touchCount: UInt64)
func liftUpAtPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64)
func touchDown(_: CGPoint)
func touchDown(_: CGPoint, touchCount: UInt64)
func touchDownAtPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64)
func shake()
func setRinger(_: Bool)
func holdVolumeDown(_: Double)
func clickVolumeDown()
func holdVolumeUp(_: Double)
func clickVolumeUp()
func holdLock(_: Double)
func clickLock()
func lockDevice()
func holdMenu(_: Double)
func clickMenu()
func _sendSimpleEvent(_: Int)
func setOrientation(_: Int32)
func sendAccelerometerX(_: Double, Y: Double, Z: Double, duration: Double)
func sendAccelerometerX(_: Double, Y: Double, Z: Double)
func _updateTouchPoints(_: UnsafePointer<CGPoint>, count: UInt64)
func _sendHIDVendorDefinedEvent(_: UInt32, usage: UInt32, data: UnsafePointer<UInt8>, dataLength: UInt32) -> Bool
func _sendHIDScrollEventX(_: Double, Y: Double, Z: Double) -> Bool
func _sendHIDKeyboardEventPage(_: UInt32, usage: UInt32, duration: Double) -> Bool
//- (_Bool)_sendHIDEvent:(struct __IOHIDEvent *)arg1;
//- (struct __IOHIDEvent *)_UIACreateIOHIDEventType:(unsigned int)arg1; func _isEdgePoint(_: CGPoint) -> Bool
func _normalizePoint(_: CGPoint) -> CGPoint
//- (void)dealloc;
func _initScreenProperties()
//- (id)init;
}

This was converted by hand from a class-dump output. If anyone knows a quicker way to do it, I'd love to know.

Once you have this protocol, you can simply do the following:

    dlopen("/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation".fileSystemRepresentation,RTLD_LOCAL)

let eventsclass = unsafeBitCast(NSClassFromString("UIASyntheticEvents"), UIASyntheticEvents.Type.self)
eventGenerator = eventsclass.sharedEventGenerator()

Looking for basic example of using Apache Felix in dynamic loading of Jar file and instancing a class at runtime in Java

If Now, simple said, I refuse to believe your problem is loading a class ... :-) I think you have quite another problem that you think can be solved to load a class?

In the majority of cases where people naively start loading classes the problem is extensibility. They have a system and want to selectively extend it with new functionality, I am making the assumption that you have a similar problem since you want to update the provider jar?

If so, download bndtools and look at OSGi services, they usually fit the bill very well

Ok, after your update. If I understand you well, you would be very well served with Apache Felix and Apache Felix File Install. File Install watches a directory and installs any bundle in that directory in the framework. Removing that jar from the directory, uninstalls the bundle. (I wrote the archetype of File Install over 12 years ago!)

For you main JAR, make it look like:

@Component(immediate=true)
public void Main {
@Reference
void setClient( Client client) { ... } // called whenever a client gets started
}

For each client JAR:

@Component
public void ClientImpl implements Client {
... whatever
}

This is virtually all you have to write when you use bndtools. Just create a component project, add a Bundle Descriptor for the main code and any number of descriptors for the client code examples, then Run As -> OSGi Run. You can then download Apache Felix File Install, add this to the run tab, and create some other projecs, drop the jars (continuously made in the generated folder) into the file install folder ... voila. Does not get much simpler than this :-)

Bad practice: exposing an event in an interface?

Well, there is one interface in particular that is probably one of the most important interfaces in .NET and it exposes one event... INotifyPropertyChanged. :)

I have never seen any recommendation against it from FxCop or the Framework Guidelines and I can't see why there would be. The only thing is if you implement the interface explicitly it becomes a pain in the butt to implement the event as you have to use the explicit add/remove accessors.

Expose new ART functionality by changing the Runtime.class of libcore

The problem:

Android ships the factory images with framework components being pre-optimised.
The file boot.oat contains pre-optimised code (or odex code), which can be accessed by reading pointers contained in the boot.art file.

These two files contain code only for the boot classpath.
The rest of the framework, and the rest of the system applications (in app and priv-app) folders have standalone odex files.

During this pre-optimisation phase, the dex code is taken out of a framework module (a jar, or an apk), is compiled using dex2oat, and the resulting code resides in the files I just mentioned.

Some of the things I 've tried:

Shipping just the libart.so and core-libart.jar does not work, even though the latter contains the dex code. This is because the runtime is still attempting to read that information from boot.oat.

By modifying the device configuration to do the pre-optimisation, the aosp build system can generate boot.oat|art and the rest of the odex files (more here). I expected that flashing all these should work, but it didn't.
(at least for the marshmallow-release branch, on a nexus6)

I 've tried flashing the whole aosp-generated build, and it didn't work, even with a custom kernel that I 've build with the security features (verity) disabled.

I am sure that some of these should have worked, but there must be something else that should be considered during building the OS.

Solution:

The last resort, was deodexing and thankfully it worked.
I have written a small script that does it for the Nexus 6 on Marshmallow.

The script, during a 1st stage, it takes out all the oat/odex code from relevant places, and de-optimises it to dex code, thanks to the oat2dex and smali projects.
On a 2nd stage, it packs the dex code back, in the framework modules (jars/apks).

Shipping a whole new core-libart.jar to the device still does not work (not sure why), but tinkering the dex files before packing them into the modules does the trick! :))

The libart.so can now find Runtime.myMethod(), which can be invoked by an application (smali tinkering again) to run my code inside ART.

How to use Java Reflections for the current application?

Cannot be done.

Java does not have a reflection system.

Research Effort

  • Get all methods with a particular annotation in a package (Question isn't about the current package. Accepted answer uses 3rd party library.)

  • Java seek a method with specific annotation and its annotation element (Question is about a specific class, rather than finding the classes)

  • How to find annotated methods in a given package?

  • How to run all methods with a given annotation?

  • getConstructor with no parameters

  • Call Methods at Runtime Using Java Reflection

  • JavaDocs - Invoking Methods

  • Default access modifier for a Java constructor

  • Can you find all classes in a package using reflection?

  • Get all methods with a particular annotation in a package (explains what a package is)

  • How to find annotated methods in a given package? (explains what a package is)
    Additional research effort

  • java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory even though I have the right dependencies

  • Oracle: Handling Initialization Status With Event Handlers

  • how to register a java class if the static initializer isn't called till the class is referenced



  • Dynamic object registration in Java
  • getConstructor with no parameters
  • Load Jar dynamically and register class(es) in applicationContext at runtime
  • Is it possible to determine descendants solely through Java reflection API?
  • Call Methods at Runtime Using Java Reflection
  • JavaDocs - Invoking Methods
  • At runtime, find all classes in a Java application that extend a base class
  • Default access modifier for a Java constructor
  • Find Java classes implementing an interface
  • Finding all classes implementing a specific interface
  • How does JUnit find tests?
  • Book: Unit Testing in Java
  • [2/28/1998: JUnit 1.0][2]
  • JUnit Cookbook
  • How can I get a list of all the implementations of an interface programmatically in Java?
  • How can I get all Class files in a specific package in Java?
  • Class Loaders in Java
  • How can I enumerate all classes in a package and add them to a List?
  • Java Reflection - Get List of Packages
  • Getting the list of packages in a java project
  • Tool to convert java to c# code
  • Package Initialization in Java
  • How to write a package-level static initializer in Kotlin?
  • https://stackoverflow.com/questions/72795950/java-initialize-all-classes-in-package-without-knowing-names
  • https://github.com/classgraph/classgraph
  • What is an initialization block?
  • Package Initialization in Java


Related Topics



Leave a reply



Submit