I'm trying to use SwiftUI in my Objective-C project, so I use this following step:
this article
after that, I'm success bridging this 2 files to my Objective-C project. but in my file SwiftUIFile.swift, my canvas cannot be resume. when I try to resume, nothing happened.
here's the code
import SwiftUI
#available (iOS 13.0, *)
struct DetailInterfacesUISwift: View {
var labelName = ""
var body: some View {
Text(labelName)
}
}
#available (iOS 13.0, *)
struct DetailInterfacesUISwift_Previews: PreviewProvider {
static var previews: some View {
DetailInterfacesUISwift()
}
}
note
1. I already delete script in build phases, nothing happen
2. I already clean project and delete core simulator downloaded
3. And still not working.
Related
The desired output looks like this,
how to show this on click event programmatically using flutter(even with native code if possible), it's really appreciated if anyone could show an example.
If there is no direct approach to this then a platform specific example using MethodChannel is also very welcome. Native code example must be in Objective C.
Additionally I have tried to use flutter_to_airplay but project fails to run and also has other functionalities that are not needed in this context, what is needed is showing Airplay panel only.
(Answer by M123 native code completely not working)
Here is a example how to open the AirPlayPanel in objective c.
Setup flutter
First you have to create a channel. To start communicating to the native code.
All channel names used in a single app must be unique; prefix the
channel name with a unique ‘domain prefix
static const platform = const MethodChannel('stack.M123.dev/airplay');
Then you have to invoke a method on the method channel.
Future<void> _openAirPlay() async {
try {
await platform.invokeMethod('openAirPlay');
} on PlatformException catch (e) {
print('error');
}
}
Native part
Now the flutter part is done.
First you have to add suppport for swift. For this open the ios folder in the flutter root with XCode.
Expand Runner > Runner in the Project navigator.
Open the AppDelegate.m located under Runner > Runner in the Project navigator.
Create a FlutterMethodChannel and add a handler inside the application didFinishLaunchingWithOptions: method. Make sure to use the same channel name as was used on the Flutter client side.
#import <Flutter/Flutter.h>
#import "GeneratedPluginRegistrant.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
FlutterMethodChannel* airPlayChannel= [FlutterMethodChannel
methodChannelWithName:#"stack.M123.dev/airplay"
binaryMessenger:controller.binaryMessenger];
[airPlayChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
// Note: this method is invoked on the UI thread.
if ([#"getBatteryLevel" isEqualToString:call.method]) {
int returnValue = [weakSelf openAirPlay];
result(#(returnValue));
}];
[GeneratedPluginRegistrant registerWithRegistry:self];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
Add the method in the AppDelegate class, just before #end
- (int)openAirPlay {
//Open air play
return (int)(100);
}
Discalimer: I am not a IOS developer so the steps are mostly theoretical.
I am following the official guide from Flutter. It can be found in full length here.
I have a very big objective-c project and am trying to incorporate SwiftUI slowly. I have been able to successfully implement some screens in swiftUI classes which are called from Objective-c classes.
One strange bug am facing now is that List is not visible when the app is run. It is visible in preview though. And also when I replace List with VStack, it appears fine when the app is run. If I make a standalone SwiftUI app and run this code, then too it runs fine. The issue is only when I call this class from objective-c class.
Attached images
Xcode Preview Screenshot
Device Screenshot
Code
import SwiftUI
struct InfoShareView: View {
var body: some View {
List{
Text("First Line")
Text("Second Line")
}
.padding()
.background(Color.white)
}
}
struct InfoShareView_Previews: PreviewProvider {
static var previews: some View {
InfoShareView()
}
}
And here is the call to InfoShareView
import UIKit
import SwiftUI
class AboutViewControllerSwift: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swiftController = UIHostingController(rootView: InfoShareView())
addChild(swiftController)
swiftController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(swiftController.view)
swiftController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
swiftController.view.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
And here is the call from objective-c class
AboutViewControllerSwift *aboutViewController = [[AboutViewControllerSwift alloc] initWithNibName:nil bundle:nil];
self.nvgController=[[UINavigationController alloc]initWithRootViewController:aboutViewController];
self.window.rootViewController=self.nvgController;
[self.window makeKeyAndVisible];
I think this is due to constraints, try use instead following
...
view.addSubview(swiftController.view)
swiftController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
swiftController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
swiftController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
swiftController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
Adding this to the last line of viewdidload worked for me:
swiftController.view.frame = self.view.frame
I am creating a messaging app with SwiftUI, and I want to add video calling function to that. I used SkyWay webRTC API (https://webrtc.ecl.ntt.com/en/) to achieve this and I could build an example project written in swift code. Now what I am trying is linking local stream with SKWVideo view and wrapping it up into UIViewRepresentable. But I got stuck with bellow error message.
import SwiftUI
import SkyWay
import UIKit
struct ContentView: View {
#State var video = SKWVideo()
var body: some View {
VideoView(localStreamView: $video)
}
}
struct VideoView: UIViewRepresentable {
#Binding var localStreamView: SKWVideo
func makeUIView(context: Context) -> SKWVideo {
let option: SKWPeerOption = SKWPeerOption.init()
option.key = "xxxx"
option.domain = "localhost"
let peer = SKWPeer(options: option)
SKWNavigator.initialize(peer!)
let constraints: SKWMediaConstraints = SKWMediaConstraints()
let localStream = SKWNavigator.getUserMedia(constraints)
localStream?.addVideoRenderer(localStreamView, track: 0)
return localStreamView
}
func updateUIView(_ uiView: SKWVideo, context: Context) {
//
}
}
I got this error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
I ran it on a iPhone 7 real device, and I wrote plist settings. I have completely no idea right now. Please help me..
iOS 13.0
xcode 11.0
I've been struggling to find a supported solution to encode images (from assets) and photo picker to base64string.
I can do this via Swift in a straight native app.
func convertImageTobase64(format: ImageFormat, image:UIImage) -> String? {
var imageData: Data?
switch format {
case .png: imageData = image.pngData()
case .jpeg(let compression): imageData = image.jpegData(compressionQuality: compression)
}
return imageData?.base64EncodedString()
}
var mylogo: UIImage? = UIImage.init(named: "DFU-180x180")
let base64String = convertImageTobase64(format: .png, image: mylogo!)
let dataString = "data:image/jpg;base64," + base64String!
I tried to do this via NativeModules, but I get errors for RCTConvert being run on background thread instead of main.
Images.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#interface Images : NSObject <RCTBridgeModule>
#end
Images.m
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Images.h"
#implementation Images
RCT_EXPORT_MODULE()
// All the methods are implemented in a Swift extension, see FileBridgeExtension.swift
RCT_EXTERN_METHOD(convertImageTobase64:(nonnull NSString*)format image:(nonnull UIImage*)image callback:(RCTResponseSenderBlock))
#end
ImagesExtension.swift
import UIKit
public enum ImageFormat {
case png
case jpeg(CGFloat)
}
#objc extension Images {
#objc func convertImageTobase64(_ format: NSString, image:UIImage, callback: #escaping ([Any]?)->Void) {
var imageData: Data?
print("convertImageTobase64_line 1")
print("convert format: " + (format as! String))
switch format {
case ".png": imageData = UIImagePNGRepresentation(image)
print("convertImageTobase64_line 2")
case ".jpeg": imageData = UIImageJPEGRepresentation(image, 1.0)
print("convertImageTobase64_line 3")
default:
print("convertImageTobase64_line 4")
let error = RCTMakeError("Invalid image format", nil, nil)
callback([[error], []]);
}
let base64string = imageData?.base64EncodedString()
print("convertImageTobase64_line 5 = " + base64string!)
callback([[NSNull()], [base64string]]);
}
}
I've tried 4 different React Native libraries and nothing works. I get errors that the library doesn't exist, even thought I do the npm install and confirm the library exists in node_modules. I even remove the node_modules folder, and rebuild it with npm install.
2 of the libraries that I've tried.
npm version that I'm using is: 6.4.1
node version that I'm using is: 8.12.0
Xcode v10
react-native-image-base64
react-native-image-to-base64
You can use this package rn-fetch-blob, it has this function File Stream which will serve your purpose.
Hope this helps you.
If you want further assistance, do ping me by commenting this post.
After experimenting with a few little Swift programs, I decided my next step was to port a single module in an Objective-C program into Swift to see what steps were required. I had a number of issues, so I thought I'd post my process and results here in case others might find it useful.
I also created a table to help me remember the different conversions. Unfortunately, StackOverflow doesn't support tables, so I posted these conversions as a Github gist here.
Although Apple will undoubtedly provide an Xcode Refactor to convert from Objective-C to Swift, converting one manually is a great way to get familiar with the differences between the two languages. There is so much 'muscle memory' involved in a language you know well, and this is a great way to get familiar with the new syntax. As promised by Apple, it turns out the languages share so many common ideas, that it's mostly a mechanical process (as opposed to porting from, say C++ or even traditional C).
Note that this process uses none of the exciting new features of Swift, it only gets the code straight across. I should mention that moving to Swift will restrict any backwards compatability to iOS 7 or OS X 10.9. I also ran into a couple of issues (with workarounds below) that I'm sure are just due to the first beta release status of the project, so may not be required in future versions.
I chose iPhoneCoreDataRecipes and picked a module that didn’t rely on a lot of others: IngredientDetailViewController. If you'd like to follow along, check out my "answer" below.
Hope this is of use.
0) Download a copy of the project here and open Recipes.xcodeproj in Xcode version 6.
1) Choose File>New File…>iOS Source>Swift File> IngredientDetailViewController (Folder: Classes, Group: Recipe View Controllers)
2) Reply Yes to “Would you like to configure an Objective-C bridging header?”
3) Copy the first three lines below from Recipes_Prefix.pch and the next three from IngredientDetailViewController.m into Recipes-Bridging-Header.h. If you do further files, obviously don't duplicate lines, and remove any files that you've converted to Swift. I haven't found any where that documents the need for the Cocoa lines, given that they're imported in the swift file, but ...
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import "Recipe.h"
#import "Ingredient.h"
#import "EditingTableViewCell.h"
4) Copy/paste the text from both the IngredientDetailViewController.h file and the IngredientDetailViewController.m files into IngredientDetailViewController.swift.
5) Delete both IngredientDetailViewController.h and .m files from project.
6) Do a global Find-and-Replace from #import "IngredientDetailViewController.h" to #import "Recipes-Swift.h" (Only one conversion in this case, and again for further files, don't duplicate this line in your Objective-C modules.)
7) Check the Project>Targets>Recipes>Build Settings Runpath Search Paths. If it shows $(inherited), remove this line or you'll get an error on launch about "no image found"
8) Convert Objective-C syntax in IngredientDetailViewController.swift to Swift. See the GitHub Gist mentioned above the substitutions required, or below for my converted version.
9) You may need to update the IB links. Do a Find>Find in Files on IngredientDetailViewController and select the one in Interface Builder. Open the Identity Inspector in the right-hand column. Select IngredientDetailViewController in the Class field, type xxx or something and tab.
10) Build and Run. Note that after going into a recipe, you must tap Edit and then the info button of an ingredient to activate IngredientDetailViewController
12) Congrats on building your first mixed Swift/Objective-C program!
Here's my cut at this particular module:
``
class IngredientDetailViewController: UITableViewController {
var recipe: Recipe!
var ingredient: Ingredient! {
willSet {
if let newIngredient = newValue {
self.ingredientStr = newIngredient.name
self.amountStr = newIngredient.amount
} else {
self.ingredientStr = ""
self.amountStr = ""
}
}
}
init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
super.init(nibName:nibNameOrNil, bundle: nibBundleOrNil?)
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
init(style: UITableViewStyle) {
super.init(style: style)
}
// MARK: table's data source
var ingredientStr: String?
var amountStr: String?
// view tags for each UITextField
let kIngredientFieldTag = 1
let kAmountFieldTag = 2
override func viewDidLoad () {
super.viewDidLoad()
self.title = "Ingredient"
self.tableView.allowsSelection = false
self.tableView.allowsSelectionDuringEditing = false
}
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let IngredientsCellIdentifier = "IngredientsCell"
let cell = tableView.dequeueReusableCellWithIdentifier(IngredientsCellIdentifier, forIndexPath: indexPath ) as EditingTableViewCell
if (indexPath.row == 0) {
// cell ingredient name
cell.label.text = "Ingredient"
cell.textField.text = self.ingredientStr
cell.textField.placeholder = "Name"
cell.textField.tag = kIngredientFieldTag
}
else if (indexPath.row == 1) {
// cell ingredient amount
cell.label.text = "Amount"
cell.textField.text = self.amountStr
cell.textField.placeholder = "Amount"
cell.textField.tag = kAmountFieldTag
}
return cell
}
#IBAction func save (sender: AnyObject!) {
if let context = self.recipe.managedObjectContext {
if (!self.ingredient) {
self.ingredient = NSEntityDescription.insertNewObjectForEntityForName("Ingredient",
inManagedObjectContext:context) as Ingredient
self.recipe.addIngredientsObject(self.ingredient)
self.ingredient.displayOrder = self.recipe.ingredients.count
}
// update the ingredient from the values in the text fields
let cell = self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow:0, inSection:0)) as EditingTableViewCell
self.ingredient.name = cell.textField.text
// save the managed object context
var error: NSError? = nil
if !context.save( &error) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate.
You should not use this function in a shipping application, although it may be
useful during development. If it is not possible to recover from the error, display
an alert panel that instructs the user to quit the application by pressing the Home button.
*/
println("Unresolved error \(error), \(error!.userInfo)")
abort()
}
}
// if there isn't an ingredient object, create and configure one
self.parentViewController.dismissViewControllerAnimated(true, completion:nil)
}
#IBAction func cancel(sender: AnyObject!) {
self.parentViewController.dismissViewControllerAnimated(true, completion:nil)
}
func textFieldDidEndEditing(textField:UITextField) {
// editing has ended in one of our text fields, assign it's text to the right
// ivar based on the view tag
//
switch (textField.tag)
{
case kIngredientFieldTag:
self.ingredientStr = textField.text
case kAmountFieldTag:
self.amountStr = textField.text
default:
break
}
}
}