• 英 文 原 文 : Mobile Little White, 30 days to Master the Flutter Dual-end Plug-in Development – Part 1
  • 英 文 原 文 : Mobile Terminal Little White, 30 days to Master Flutter dual end plug-in Development – (Android)

It has been a month and a half since the last article, the main two ends have been developed, can not continue to pay learning, need to do something real, let so long hard work to play its due value – on the shelf. Android needs to be put on every App Store, iOS App Store, the first time to do this work is more than hard technology but also exhausting, a sad tears flowing in my heart, even light fun can water 2000 words. I helped my colleagues improve the company’s back office management system, and also developed another camera plug-in. That will come later.

Passed to the Android development, we have all the basic functions in the plug-in touch clear, also the normal run through in the project, in principle, now you just need to know about the double side development difference, converting kotlin code, swift code, and these functions involve permissions apply to exist on the iOS side again. What about going through the documentation, understanding the development differences, and giving me three days to get it done? Laughed at the thought.

But when it came time to get started, I found myself Too young, Too simple. You have to prepare your developer account, you have to download the xCode editor that you have to use, you can’t read the xCode file directory, you can’t use the official document search function, you have to pay $100 if you want to package it and send it to your colleagues for testing, and many other problems. The last time I felt this bad was when I used my iPhone for the first time. I used it for a month. I went back to Android.

The joke is that other programming languages use familiar words for reserved words and error statements, but Apple had to invent one that doesn’t defy logic, but defies common sense.

There is more eggs hurt, is the feeling of iOS articles are particularly few, free classes are backward knowledge, paid system class time is too long, no time to learn, and redundant knowledge is not used.

After teasing, let’s get down to business.

Xcode file directory

Without further discussion, let’s take a look at the comparison between Android and iOS. The first thing we can see is the difference in the file directory. I occasionally worked with the Android directory files on a daily basis during the development of The Flutter, and they were straightforward, SRC, RES, and Grale 100 were all over the place, so I did not introduce the directory in my mid-part. But in the iOS directory, it took half a day to find a place to write code.

Again, right-click the project directory, place the cursor on the Flutter option, and click the sub-option Open iOS Module in Xcode to see the iOS code file.

directory folder Include function description
Runner Flutter Xcconfig Project configuration file
Runner Main program code written file, permission configuration file
Products App runs the program, can not run directly
Pods Third-party plug-in configuration file
Frameworks The Pods of the library
Pods Podfile (documents) Pods dependency description file
Development Pods Plug-in development is a place to write code
Frameworks Save the official provided plug-in
Products The plug-in itself is also a Freamwork
Targets Support Files Some configuration files for Pods

(Only a few of the above directories are available to us, and the descriptions are very inaccurate. They are written according to our own understanding.)

The Runner part of this is in the root /example/ios directory, some of the configuration of the project needs to be changed here, and this is the one that actually runs, the Pods are in the root /ios directory, and this is where we’re writing the main method.

Ii. Swift for the future

Now that you know where to write, it’s time to learn how to write.

Languages for the same purpose will have many similar places. After learning the Android development language, and then learning iOS, we will find that there are many concepts in the same place, which can also reduce our mental burden.

As we all know, iOS has two languages to choose from, the old object-C and the new Swift. Any language is the older the more stable, more information, more resources, but lack of modern language functions; A new language is always unstable, has a lot of changes, little data problems, grammar refinement, and a lot of good modern features. Today, Swift is in its seventh year and fifth major release, and the problem of instability is minimal. The most important thing is that the code of the same function is less and easier to understand, after all, the code is mainly for people to see.

So, based on the experience of buying a phone with a computer, come out SWIFT!!

10000+ words long | Swift grammar comprehensive analysis, this is the most complete LANGUAGE I see the introduction.

1. Data type

Dart uses null, bool, int, String, Map, and Uint8List to look at the table:

I’m sure you’re familiar with all the other data, but it’s the same here, the way to understand the different data types. The main thing to notice about TypedData is that when passing this type of data to the flutter, it needs to be wrapped in FlutterStandrdTypedData.

  • Swift String String
  • Swift – Basic operation

2. Basic grammar

We don’t use a lot of grammar in this project, so the key is to learn what we use. By the way, the main reason why WE didn’t choose OC is that dart, Kotlin, and Swift have one big thing in common. They are all languages with null Salfty mechanism, which is more in line with our thinking habits.

Variables and Constants

The first step in any language is to declare variables.

  • Constants and variables must be declared before use.
  • Use var to declare variables that can be read or written.
  • Let to declare constants, which can only be determined at declaration time.
  • The declaration can specify the type of the value, or it can automatically determine that the type cannot be changed.
// Declare a constant
let TAG:String = "plugin"
// A variable can be reassigned
var status: NSNumber = 0
// An empty variable that will be assigned later
var img:UIImage?
Copy the code

Process control

Swift has for in loops, while loops,if conditions, switch judgments, ternary operations.

// The for in loop can also loop through the dictionary to get keys and values
let names = ["Anna"."Alex"."Brian"."Jack"] 
for name in names { 
    print("Hello, \(name)!")}/ / while loop
var index = 10
while index < 20 {
   print( "The value of index is (index)")
   index = index + 1
}

/ / if judgment
if index > 20 {
   print( "Value of index greater than 20")}else {
   print( "Value of index is less than 20")}/ / the switch judgment
switch index {
   case 100  :
      print( "The value of index is 100")
   case 10.15  :
      print( "The value of index is 10 or 15")
   case 5  :
      print( "The value of index is 5")
   default :
      print( "The default case")}// Ternary operation
index > 20 ? print( "Value of index greater than 20") : print( "Value of index is less than 20")
Copy the code

Functions and expressions

Use func to declare a function. You can declare the type of the parameter passed and the value returned.

// There is no return value. The return value type can be omitted
func getInfo(name: String.site: String) -> String {
    return name + site
}
Copy the code

closure

Closures work a bit like Lambda expressions in other languages, but in this case they’re a bit abstract. Check out closures in this article, Swift.

Closure is difficult to understand, but we only need to know how it is declared and implemented. Through the example, it can be simply understood as using {} plus in keyword, and can use the parameters of the closure.

// Closure declaration
var closure: ((String.Int) - >String)! 

// Closure implementation
closure = { (name, age) in 
    return "\(name)is\(age)At the age of" 
}
Copy the code

Class class

Classes in all programming languages are much the same. We can define attributes and methods for the class, call our own methods and familiarization inside the class using the self keyword, and SWIFT automatically generates external interfaces to other code.

class Marks {
    var mark: Int
    init(mark: Int) {
        selfmark = mark
    }

    func suffix(mark: Int) -> String{
        return "\(mark)Points"
    }

    func getSuffix(a) -> String {
        return selfsuffix(mark: selfmark)
    }
}

let m1 = Marks(mark: 100)
print(m1.getSuffix())
// Print: 100 points
print(m1.suffix(50))
// Print: 50 points
Copy the code

Although the syntax is similar to kt, many of the concepts are very abstract. Of course, when you start learning, you don’t need to know those concepts, you just need to think of it as a black box, and if you write it the same way, you can input whatever parameters you want to output.

Iii. Functional realization

The process here is still very similar to that on Android, just importing the plug-in – executing the plug-in. But the biggest differences between platforms are not in coding, but in project configuration, directory structure, plug-in imports and other development expenses.

1. Pods

The first is the main project file, and the second is pods. The second is the so-called Cocoapods, which is a dependency management tool for iOS projects, similar to Android Gradle. Pubspec for Flutter, and NPM for front-end development.

Installing remote dependencies

Installing third party dependencies on ios can be configured directly in the file just like The Flutter, in this case it can be configured directly in the Pods/Podfile file.

target 'QSAppDemo' do
  pod 'AFNetworking'
  pod 'YYModel', '~ > 1.0.4'
  pod 'OOMDetector', '1.3'#This parameter is valid in Debug mode
  pod 'FLEX', '~ > 2.0', :configurations = > ['Debug']
  pod'WebViewJavascriptBridge',:git= >'https://github.com/marcuswestin/WebViewJavascriptBridge.git'
end
Copy the code

Installing local Dependencies

Add the following configuration directly to the Development Pods/{project name}/Pod/{project name}.podspec file

// Reference the framework library
s.vendored_frameworks = "{path}/{filename}.framework"
// Reference the static library
s.vendored_libraries = "{path}/{file name}.a"
// Reference the header file
s.source_files = "{path} / / * * *"
Copy the code

After all the above configurations are complete, you must use the pod install command to download the third-party library, or the POD Update command to update the configuration file for the dependency to take effect.

Native dependence

In addition to third-party dependencies, you also need to add official native dependencies, again in the. Podspec suffix file with the following configuration.

// Reference the framework library
s.frameworks = "NetworkExtension"."CoreLocation"
// Reference the dynamic libraries. Lib and TBD, and remove the ending lib and TBD
s.libraries = "bz2.1.0.5"."Iconv. 2.4.0." "."z"."c++"
Copy the code

To get the file name here, and to see if the configuration was successful, click on Pods directly to open the Pods.xcodeProj visual edit file.

Click Target-Project name on the left to open the configuration of the project, and click Build Phases-Link Binary With Librarys to see the dependencies.

You can use notes in Cocoapods to learn the details of Cocoapods use

2. Import local dependencies

Since we are using a local dependency in our project and it is a framework, all we need to do is import the dependency into the project and configure the podspace file.

File to import

In the Flutter project, open the ios directory, create a new Freamwork folder, and copy and paste your local dependencies into it.

The pods to update

Open the XCode editor and add the following configuration to the.PodSpec file in Your Pods

// Reference the framework library
s.vendored_frameworks = "Framework/*.framework"
Copy the code

Open the command line tool again and execute pod Update

The local dependency is no longer displayed in Link Binary With Librarys. You can directly import the dependency from the encoded file. If a prompt is displayed, the dependency is imported successfully.

3. Data interaction initialization

The similarities between Kotlin and Swift begin to appear here as you begin to formally write business code

import Flutter
import UIKit
import CoreLocation
import CoreTelephony
import HZCameraSDK
import Foundation

public class SwiftHzCameraPlugin: NSObject.FlutterPlugin.HZCameraSocketDelegate{
    
var cllocationManager: CLLocationManager!
var eventSink:FlutterEventSink?
var mPrevivew: HZDisplayView = HZDisplayView(a)var img:UIImage?
public static let instance: SwiftHzCameraPlugin = SwiftHzCameraPlugin(a)// Data stream listener
class SwiftStreamHandler: NSObject.FlutterStreamHandler {
 func onListen(withArguments arguments: Any?.eventSink events: @escaping FlutterEventSink) -> FlutterError? {
  instance.eventSink = events
  return nil
 }

 func onCancel(withArguments arguments: Any?) -> FlutterError? {
  instance.eventSink = nil
  return nil}}public static func register(with registrar: FlutterPluginRegistrar) {
/ / bind MethodChannel
  let channel = FlutterMethodChannel(name: "hz_camera", binaryMessenger: registrar.messenger())
  / / bind EventChannel
  let eventChannel = FlutterEventChannel(name: "HzCamera_event", binaryMessenger: registrar.messenger())
  eventChannel.setStreamHandler(SwiftStreamHandler())

  registrar.addMethodCallDelegate(instance, channel: channel)
}

}

Copy the code

4. Implementation method

Android and iOS have a little bit of a difference in terms of permissions and connecting hardware, but the whole thing is the same.

To apply for permission

func checkPermission(a) {
    CTCellularData().cellularDataRestrictionDidUpdateNotifier = { (state) in
     if state = = CTCellularDataRestrictedState.restrictedStateUnknown {
      DispatchQueue.main.async {
       self.requestWLANAuth()
      }
     }
     else if state = = CTCellularDataRestrictedState.restricted {
       DispatchQueue.main.async {
         self.requestWLANAuth()
       }
     }
    }
}
Copy the code

Connect the camera

// 2. Connect the camera
func connectCamera(a) {
  do {
    try HZCameraConnector.default().connectToCameraError()
  } catch let error {
   self.eventSink!([
    "code": 0."data": "Connection failed",]as [String: Any])}// Initialize the camera directly after the connection is successful
  setUpCamera()
}
Copy the code

Executed when the camera connection status changes

// 3, when the camera connection status changes
public func cameraConnectionStateChange(_ state: E_SOCKET_STATE) {
 if E_SOCKET_STATE_CONNECTED ! = state {
  NSLog("Camera disconnected")}else {
  NSLog("Camera connected")
  setUpCamera()
 }
}
Copy the code

The camera is initialized and permissions are obtained

Android only needs to initialize once to connect to the camera, so let’s put this method first, whereas iOS needs to initialize every time you connect to the camera.

// 4. Initialize the camera
func setUpCamera(a) {
 requestWLANAuth()
 HZCameraMedia.default().setupCamera(
  completion: {},
  fail: {(err) in
   
  },
  progress: {(process) in})}Copy the code

Start & end preview

Calling the Preview data method gets the RGB image data, which can be passed to the Flutter layer for rendering.

// 5, start preview
func startPreview(a) {
 mPrevivew.startGetRgbData({ (data: Data, w: Int32, h: Int32) in
  self.eventSink!([
   "code": 1."data": [
    "frameData": FlutterStandardTypedData(bytes: data),
    "width": w,
    "height": h
   ],
  ] as [String: Any])
 }, fail: { (err) in
  NSLog(err.localizedDescription)
 })
}

func stopPreview(a) {
  mPrevivew.stop()
}
Copy the code

Taking pictures

// 6
func takePhoto(a) {
 // Get the camera address
 HZCameraMedia.default().onlyTakePhoto() { (picAddress) in
  // Take the photo successfully to splice the photo
  self.genPanoramaPhoto(path: picAddress)
 } cameraStatus: { (status: E_TURN_STATUS) in
  // Camera status
 } fail: { (err) in
  // Failed to shoot}}Copy the code

Joining together photos

// 7
func genPanoramaPhoto(path: String) {
 let homedDirectory = NSHomeDirectory(a)+"/Documents/"
 
 HZCameraFileManager.default().setAlbumLocalAddress(homedDirectory)
 HZCameraFileManager.default().getPhotoWithName(path) { (img) in
  // The path of the photo
 } fail: { (err) in
  // Splicing failed
 } progress: { (process) in
  // The splicing process}}Copy the code

Get camera parameters

// 8, get camera parameters
func getSystemInfo(result: @escaping  FlutterResult) {
 HZCameraSettings.default().getCameraMemoryInfo {(info) in
  result([
   "mBatteryPercent": info.chargeInfo,
   "mChargingState": info.batteryStatus = = E_BATTERY_CHARGING ? "Charging" : "Uncharged"."freeMemorySpaceWithUnitG": String(format: "%.2f".Float(info.memoryFreeStorage)/1000),]as [String: Any])
 } fail: { (err) in
  print(err)
 }
}
Copy the code

5. Return data to the Flutter layer

Data communication is still the two basic methods, result timely return data and event real-time listening data.

Return data in time

For example, get camera parameters

result([
   "mBatteryPercent": info.chargeInfo,
   "mChargingState": info.batteryStatus = = E_BATTERY_CHARGING ? "Charging" : "Uncharged",]as [String: Any])
Copy the code

In Android, we use a hashMap type to pass arguments, while in iOS we use a Dictionary type, so we can declare a Dictionary type using [] as [String:Any].

Monitor real-time data

Camera images are dynamic and need to be monitored for image data and refreshed in real time.

// Declare the event method in the project initialization.
var eventSink:FlutterEventSink?
self.eventSink!([
 "code": 1."data": [
  "frameData": FlutterStandardTypedData(bytes: data),
  "width": w,
  "height": h
 ],
] as [String: Any])
Copy the code

The picture data is Unit8List, so it needs another layer of packaging to be transmitted to the Flutter.

Four,

In fact, it only took about 8 working days to learn SWIFT. After learning DART and Kotlin, we can learn Swift once again and write some small examples. These functions have already been done on android, just rewrite them and adjust the interface execution process according to the differences between the two ends.

It sounds simple, but the first step of iOS development, familiarizing yourself with the Xcode directory and importing plug-ins, took 5 days. It also took several tuition fees to ask iOS development leaders, and it took 13 days in total.

These enhancements are only a glimpse into native development, with kotlin and Swift just scratching the surface and understanding the two-end project development process. For the native layout, all the other native features are not yet involved and need more practice to master more knowledge.

After completing these functions for a month, I was free to write this short article. And this period of time to develop another plug-in, had to use the native layout, with PlatformView, master the programming language and layout method, like front-end learned HTML5 + JS, can do all can do, is more entry native development, and can water 2 articles, of course, that is later.