Cookie Consent by Free Privacy Policy Generator ๐Ÿ“Œ How to build a Barcode Widget in React Native (part II: iOS)

๐Ÿ  Team IT Security News

TSecurity.de ist eine Online-Plattform, die sich auf die Bereitstellung von Informationen,alle 15 Minuten neuste Nachrichten, Bildungsressourcen und Dienstleistungen rund um das Thema IT-Sicherheit spezialisiert hat.
Ob es sich um aktuelle Nachrichten, Fachartikel, Blogbeitrรคge, Webinare, Tutorials, oder Tipps & Tricks handelt, TSecurity.de bietet seinen Nutzern einen umfassenden รœberblick รผber die wichtigsten Aspekte der IT-Sicherheit in einer sich stรคndig verรคndernden digitalen Welt.

16.12.2023 - TIP: Wer den Cookie Consent Banner akzeptiert, kann z.B. von Englisch nach Deutsch รผbersetzen, erst Englisch auswรคhlen dann wieder Deutsch!

Google Android Playstore Download Button fรผr Team IT Security



๐Ÿ“š How to build a Barcode Widget in React Native (part II: iOS)


๐Ÿ’ก Newskategorie: Programmierung
๐Ÿ”— Quelle: dev.to

In this tutorial we are going to learn how to build a barcode widget for an iOS device.
In the previous part we focused on Android and Java, while in this part we're going to be using Swift.
The process will be similar in many ways, except for the bridging method, which is going to slightly differ.

In part I of this series we will show how to create Android widget using Java.

1. Intro

In order to build the widget we will be creating a simple extension in xCode as well as a "bridge" that will allow our app to communicate with the widget. Let's begin!

2. Creating the widget

We can start by opening our project in xCode. Now, right click on the project folder and navigate to file > new > target.

Image description

This will open a new window with different extensions. Let's search for the "Widget Extension".

Image description

Next, we can select the product name of our widget.

Image description

I am going to name it "BarcodeWidget". Make sure to uncheck โ€œInclude Configuration Intentโ€ and "Include live activity".

If we click the finish button, xCode is going to ask us if we want to create an active scheme. Select "activate".

Image description

Now, we can select our widget extension in the "targets" section and run it. Be sure to run it for iOS 14.0 and up, as the previous versions of iOS aren't compatible with the extension.

At this point, we should be able to see our widget on the home screen. For now, it is only displaying a simple date.

Image description

Let's take a look at the files created in our project. We can see that xCode created a new folder with the same name we set for the widget at the beginning.

Image description

To modify our widget we can open the "BarcodeWidget.swift" file.
There are different functions and structures inside the file. Let's take a look at a few of them:

  • "BarcodeWidget struct" deals with the main configuration of our widget. Here, we can set the display name as well as the widget's description. If we'd like our widget to be non-resizable and of a specific size (the default preview offers three options: small, medium and large) we can set it here by calling the supportedFamilies() function and passing it an argument, an array that contains our preferred widget sizes.

.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])

Image description

  • Next, there is the "BarcodeWidgetEntryView" struct where we can modify the widget's layout.
struct BarcodeWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        Text(entry.date, style: .time)
    }
}
  • You may also find the "getTimeline() method". It provides an array of timeline entries for the current time and, optionally, any future times to update a widget.
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
            let entry = SimpleEntry(date: entryDate)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }

If you want a better understanding of the TimelineProvider and its functions, you can always check Apple's official documentation in here.

3. Bridging

To display data from our React Native app, we are going to need some additional settings.
First, let's add the "App Group" capability to our project in order to let the widget communicate with the app.
Find your main app target in the Xcode project settings, switch to the Signing & Capabilities tab and click on + Capability.

Image description

Then search for "App Groups" and double click on it.

Image description

Click the + button in the new "App Groups" capability created and choose your team. The final step is to add an app group identifier. After you finish, you should see your App Group id appear. If it comes up red - make sure to try the refresh button.

Image description

Now, we can do the same thing for our widget's target. We can open the widget's Signing & Capabilities tab and add a new "App Groups" capability. If we select the same team as before, we should be able to see the identifier we already created in our main project's target. Make sure the same id is selected on both targets.

We have to set one more thing before we start writing our code in React Native. This includes installing the "SharedGroupPreferences" package. From the terminal, run:

npm i react-native-shared-group-preferences

Open your App file and import:

import SharedGroupPreferences from 'react-native-shared-group-preferences'

Now, let's add this to our code:

  // Let's display a random 6 digit number
  const barcode = Math.floor(100000 + Math.random() * 900000).toString()

  const appGroupIdentifier = 'group.widget.barcode.jp'

  useEffect(() => {
  if (Platform.OS === 'ios'){
      const setWidgetData = async () => {await SharedGroupPreferences.setItem('widgetKey', {
        text: barcode !== undefined ? barcode : '',
      }, appGroupIdentifier)}
      setWidgetData()
        .catch((error) => {
          log.info(() => ['error setting widget data, err: ', error])
  },[barcode])

The "appGroupIdentifier" should be the same as the one we just set in our "App Groups".

Great! We are done with the React Native part. Now, let's go back to our widget's code.

To add new text to our widget, first we have to add the following code above our Provider:

struct WidgetData: Decodable {
var text: String
}

Next, update the "SimpleEntry" struct:

struct SimpleEntry: TimelineEntry {
let date: Date
let myString: String
}

Variable "myString" is going to be our barcode string that we set in the React Native app. When we add this, an error is going to come up - telling you to update the number of arguments of certain methods. After fixing this error, our code should look something like this:

Image description

Now let's update our "getTimeline()" method with the following code:

func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
    var entries: [SimpleEntry] = []

    let userDefaults = UserDefaults.init(suiteName: "group.widget.barcode.jp")
    if userDefaults != nil {
      if let savedData = userDefaults!.value(forKey: "widgetKey") as? String {
        let decoder = JSONDecoder()
        let data = savedData.data(using: .utf8)
        if let parsedData = try? decoder.decode(WidgetData.self, from: data!) {
          let currentDate = Date()
          let entryDate = Calendar.current.date(byAdding: .second, value: 3, to: currentDate)!

          let entry = SimpleEntry(date: entryDate, myString: parsedData.text)
          entries.append(entry)

          let timeline = Timeline(entries: entries, policy: .atEnd)
          completion(timeline)
        } else {
          print("Could not parse data")
        }
      } else {
        let currentDate = Date()

        for hourOffset in 0 ..< 2 {
          let entryDate = Calendar.current.date(byAdding: .second, value: hourOffset, to: currentDate)!
          let entry = SimpleEntry(date: entryDate, myString: "No data")
          entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
      }
    }
  }

Replace the "suiteName" value with your own App Group ID in the following line:

UserDefaults.init(suiteName: "group.widget.barcode.jp")

The last thing to set before running our widget again is the "BarcodeWidgetEntryView" struct.
In order to display the barcode text from the React Native app - let's add this:

`struct BarcodeWidgetEntryView : View {
var entry: Provider.Entry

var body: some View {
   Text(entry.myString).font(.system(size: 12)).tracking(2)
}

}`

Remember to run pod install in your iOS folder.
Now, let's start the app.

If everything works well, the barcode number we previously set in our app will be displayed on the widget.

Image description

4. Generating the barcode image from a string value

The only thing that's left to do includes generating a barcode image from our barcode number as well as displaying it.

To do this, we are going to add a few functions to our "BarcodeWidget.swift" file.

The first function we are going to add is "generateBarcode()":

func generateBarcode(from string: String) -> UIImage? {

  let data = string.data(using: String.Encoding.ascii)

  if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
    filter.setDefaults()
    //Margin
    filter.setValue(1.00, forKey: "inputQuietSpace")
    filter.setValue(data, forKey: "inputMessage")
    //Scaling
    let transform = CGAffineTransform(scaleX: 3, y: 3)

    if let output = filter.outputImage?.transformed(by: transform) {
        let context:CIContext = CIContext.init(options: nil)
        let cgImage:CGImage = context.createCGImage(output, from: output.extent)!
        let rawImage:UIImage = UIImage.init(cgImage: cgImage)

        //Refinement code to allow conversion to NSData or share UIImage. Code here:
        //http://stackoverflow.com/questions/2240395/uiimage-created-from-cgimageref-fails-with-uiimagepngrepresentation
        let cgimage: CGImage = (rawImage.cgImage)!
        let cropZone = CGRect(x: 0, y: 0, width: Int(rawImage.size.width), height: Int(rawImage.size.height))
        let cWidth: size_t  = size_t(cropZone.size.width)
        let cHeight: size_t  = size_t(cropZone.size.height)
        let bitsPerComponent: size_t = cgimage.bitsPerComponent
        //THE OPERATIONS ORDER COULD BE FLIPPED, ALTHOUGH, IT DOESN'T AFFECT THE RESULT
        let bytesPerRow = (cgimage.bytesPerRow) / (cgimage.width  * cWidth)

        let context2: CGContext = CGContext(data: nil, width: cWidth, height: cHeight, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: cgimage.bitmapInfo.rawValue)!

        context2.draw(cgimage, in: cropZone)

        let result: CGImage  = context2.makeImage()!
        let finalImage = UIImage(cgImage: result)

        return finalImage

    }
}

This function will create an UIImage from the string.

Finally, let's update "BarcodeWidgetEntryView" by adding the following:

struct BarcodeWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
      if let image = generateBarcode(from: entry.myString) {
                          Image(uiImage: image).resizable()
                          .imageScale(.small).frame( width: CGFloat(132), height: CGFloat(60)).padding(.bottom, 3)
       }
       Text(entry.myString).font(.system(size: 12)).tracking(2)
    }
}

When we run the application again, the widget should be displaying both the text and the image, as shown below:

Image description

5. Updating the widget content

Now, let's focus on keeping our widget up to date.
First let's change our update policy to "never" since we are going to instruct the app on when to update its content.

let timeline = Timeline(entries: entries, policy: .never)

Let's create a "reloadWidget()" function in the Swift code that we are later going to call in our React Native app.
This can be done by adding two files to our project.
Select "new file" and choose "Swift File" in the next window.

Image description

Next, let's name the file "WidgetModule" and select your app as the target of this file.

Image description

Update the "WidgetModule.swift" file as shown below:

import Foundation
import AVFoundation
import WidgetKit

@objc(WidgetModule)
class WidgetModule: NSObject {

  @objc public func reloadWidget(_ kind: String) -> Void {
     if #available(iOS 14.0, *) {
       #if arch(arm64) || arch(i386) || arch(x86_64)
       WidgetCenter.shared.reloadAllTimelines()
       #endif
     }
   }

  @objc
  static func requiresMainQueueSetup() -> Bool {
    return true
  }

}

Our "reloadWidget" is using WidgetCenter.shared.reloadAllTimelines()
method to reload the widget's timeline. For more details about reloading the widget check this link.

Now we need to add the other file. Choose "Objective-C":

Image description

Let's name it the same as the file before "WidgetModule" and select the same file target as of the previously created file.

Update the file like this:

#import <Foundation/Foundation.h>

#import "React/RCTBridgeModule.h"
@interface
RCT_EXTERN_MODULE(WidgetModule, NSObject)
RCT_EXTERN_METHOD(reloadWidget: (NSString *)kind)

@end

This file will be used to export our newly created module that we are going to use later in the React Native app.

The last file that we are going to add is a Bridging Header. Again, add a new file and choose "Header".

Image description

Paste the following code:

//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "React/RCTBridgeModule.h"

Finally let's call our "updateWidget" function from the React Native code;

First, import NativeModules in the App file:

`import { NativeModules } from 'react-native'

export const App = () => {
const { WidgetModule } = NativeModules

...
}
`

Then, let's update our "useEffect" hook by adding
.then(() => WidgetModule.reloadWidget(appGroupIdentifier))
to setWidgetData() method.

The final result should look like this:


  if (Platform.OS === 'ios'){
      const setWidgetData = async () => {await SharedGroupPreferences.setItem('widgetKey', {
        text: barcode !== undefined ? barcode : '',
      }, appGroupIdentifier)}
      setWidgetData()
        .then(() => WidgetModule.reloadWidget(appGroupIdentifier))
        .catch((error) => {
          log.info(() => ['error setting widget data, err: ', error])
        })

7. The end

Alright, it looks like we are done!

Don't forget to run npm install && cd iOS && pod install before running your project again. The widget layout should now be updating every time we call the "updateWidget" function.

Feel free to play around with different widget options and try to add some style to it.

Good luck with your project, I hope this tutorial helped you!

...



๐Ÿ“Œ How to build a Barcode Widget in React Native (part II: iOS)


๐Ÿ“ˆ 64.46 Punkte

๐Ÿ“Œ How to build a Barcode Widget in React Native (part I: Android)


๐Ÿ“ˆ 60.77 Punkte

๐Ÿ“Œ This Week In React #139: React.dev, Remix, Server Components, Error Boundary, Wakuwork, React-Native, Bottom Sheet...


๐Ÿ“ˆ 36.85 Punkte

๐Ÿ“Œ This Week In React #146: Concurrency, Server Components, Next.js, React-Query, Remix, Expo Router, Skia, React-Native...


๐Ÿ“ˆ 36.85 Punkte

๐Ÿ“Œ The State of React Native Tooling (React Native CLI - The Ultimate Guide)


๐Ÿ“ˆ 36.64 Punkte

๐Ÿ“Œ React Native Networkingย โ€“ How To Perform API Requests In React Native using the FetchAPI


๐Ÿ“ˆ 36.64 Punkte

๐Ÿ“Œ Building a Modern Document Website for React Native Library Like React Native ECharts


๐Ÿ“ˆ 36.64 Punkte

๐Ÿ“Œ MW6 Technologies Barcode ActiveX 3.0.0.1 ActiveX Control Barcode.dll memory corruption


๐Ÿ“ˆ 35.58 Punkte

๐Ÿ“Œ Universal Product Code Barcode Will Be Supplanted By 2027 With a More Data-Rich '2D' Barcode


๐Ÿ“ˆ 35.58 Punkte

๐Ÿ“Œ DRPU Barcode Maker 9.2.3.1 - High resolution barcode assets tags in your own style.


๐Ÿ“ˆ 35.58 Punkte

๐Ÿ“Œ iOS 16.2: Schlaf-Widget taucht in Beta auf โ€“ Apple arbeitet an Medikamenten-Widget


๐Ÿ“ˆ 28.22 Punkte

๐Ÿ“Œ This Week In React #127: Nextra, React-Query, React Documentary, Storybook, Remix, Tamagui, Solito, TC39, Rome...


๐Ÿ“ˆ 27.8 Punkte

๐Ÿ“Œ This Week In React #131: useReducer, Controlled Inputs, Async React, DevTools, React-Query, Storybook, Remix, RN , Expo...


๐Ÿ“ˆ 27.8 Punkte

๐Ÿ“Œ This Week In React #142: React-Query, Million, OpenNext, Ariakit, Expo-Image, React-Three-Fiber, TS 5.1, Node.js 20, WebGPU...


๐Ÿ“ˆ 27.8 Punkte

๐Ÿ“Œ This Week In React #126: Perf, Progressive Enhancement, Remix, Storybook, React-Native, FlashList, Nitro, TC39...


๐Ÿ“ˆ 27.59 Punkte

๐Ÿ“Œ Share code between React Native and React Web


๐Ÿ“ˆ 27.59 Punkte

๐Ÿ“Œ React vs React Native: How Different Are They, Really?


๐Ÿ“ˆ 27.59 Punkte

๐Ÿ“Œ How to Manage State in React and React Native with the PullState Library


๐Ÿ“ˆ 27.59 Punkte

๐Ÿ“Œ React vs React Native: Pros, Cons, and Key Differences


๐Ÿ“ˆ 27.59 Punkte

๐Ÿ“Œ This Week In React #172: Next.js, PPR, Remotion, State of React Native, Parcel, Panda, Remix, Skia, Storybook, Tamagui...


๐Ÿ“ˆ 27.59 Punkte

๐Ÿ“Œ React Native vs React: Key Differences and Use Cases


๐Ÿ“ˆ 27.59 Punkte

๐Ÿ“Œ Native Web Apps: React and WebAssembly to Rewrite Native Apps


๐Ÿ“ˆ 27.37 Punkte

๐Ÿ“Œ Native Vs React Native Development: Key Differences


๐Ÿ“ˆ 27.37 Punkte

๐Ÿ“Œ TOP 6 React Native libraries with native performance โšก๏ธ


๐Ÿ“ˆ 27.37 Punkte

๐Ÿ“Œ React Beyond the Boilerplate: Unleashing Creativity with Manual Mastery - Part 1: React as a CDN


๐Ÿ“ˆ 25.51 Punkte

๐Ÿ“Œ WhatsApp UI in React Native (part 1)


๐Ÿ“ˆ 25.3 Punkte

๐Ÿ“Œ KDE's Plasma Breeze AlphaBlack v11 w/ Widget v2 can now control the popup and desktop widget transparency


๐Ÿ“ˆ 24.53 Punkte

๐Ÿ“Œ Medium CVE-2016-10991: Imdb-widget project Imdb-widget


๐Ÿ“ˆ 24.53 Punkte

๐Ÿ“Œ WP Page Builder Plugin up to 1.2.3 on WordPress Raw HTML Widget/Custom HTML Widget cross site scripting


๐Ÿ“ˆ 24.53 Punkte

๐Ÿ“Œ Widget Hub mรถchte Anlaufstelle fรผr Widget-Scripts fรผr Scriptable werden


๐Ÿ“ˆ 24.53 Punkte

๐Ÿ“Œ As if one Widget board wasnโ€™t enough, Windows 11 now lets users have 2 Widget boards


๐Ÿ“ˆ 24.53 Punkte

๐Ÿ“Œ Build a 3D World in React with ThreeJS and React Three Fiber


๐Ÿ“ˆ 23.95 Punkte

๐Ÿ“Œ Build complex PDFs using React: react-print-pdf


๐Ÿ“ˆ 23.95 Punkte

๐Ÿ“Œ Build complex PDFs using React: react-print-pdf


๐Ÿ“ˆ 23.95 Punkte

๐Ÿ“Œ Let's Build a Restaurant App with React Native


๐Ÿ“ˆ 23.73 Punkte











matomo